Как получить текущее использование памяти в Android?
Я использовал /proc/meminfo и проанализировал команду response.hover, но результат показывает, что:
MemTotal: 94348 кБ MemFree: 5784 кБ
средства. это показывает, что есть только 5 МБ свободной памяти. Возможно ли это с Android Mobile? На моем мобильном телефоне установлено только 5-6 приложений, и никакие другие задачи не выполняются. но все же эта команда показывает, что свободной памяти очень мало.
Может кто-нибудь уточнить это? или есть ли другой способ получить использование памяти в Android?
12 ответов
ВНИМАНИЕ: Этот ответ измеряет использование памяти / доступное УСТРОЙСТВА. Это НЕ то, что доступно для вашего приложения. Чтобы оценить, что делает ваше приложение и РАЗРЕШЕНО, используйте ответ разработчика Android.
Документы для Android - ActivityManager.MemoryInfo
команда parse /proc/meminfo Вы можете найти код ссылки здесь: Получить использование памяти в Android
используйте код ниже и получите текущую оперативную память:
MemoryInfo mi = new MemoryInfo(); ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE); activityManager.getMemoryInfo(mi); double availableMegs = mi.availMem / 0x100000L; //Percentage can be calculated for API 16+ double percentAvail = mi.availMem / (double)mi.totalMem * 100.0;
Пояснение к номеру 0x100000L
1024 bytes == 1 Kibibyte
1024 Kibibyte == 1 Mebibyte
1024 * 1024 == 1048576
1048576 == 0x100000
Совершенно очевидно, что число используется для преобразования из байтов в мебибайт
PS: нам нужно рассчитать общий объем памяти только один раз. поэтому вызывайте точку 1 только один раз в своем коде, а затем после, вы можете повторно вызывать код точки 2.
Это зависит от вашего определения, какой запрос памяти вы хотите получить.
Обычно вы хотите знать состояние кучи памяти, поскольку, если она использует слишком много памяти, вы получаете OOM и вылетаете из приложения.
Для этого вы можете проверить следующие значения:
final Runtime runtime = Runtime.getRuntime();
final long usedMemInMB=(runtime.totalMemory() - runtime.freeMemory()) / 1048576L;
final long maxHeapSizeInMB=runtime.maxMemory() / 1048576L;
final long availHeapSizeInMB = maxHeapSizeInMB - usedMemInMB;
Чем больше переменная "usedMemInMB" приближается к "maxHeapSizeInMB", тем ближе availHeapSizeInMB
достигает нуля, чем ближе вы получаете ООМ. (Из-за фрагментации памяти вы можете получить OOM ДО того, как это достигнет нуля.)
Это также то, что показывает инструмент использования памяти DDMS.
Кроме того, существует реальное использование ОЗУ, то есть то, сколько использует вся система - см. Принятый ответ, чтобы рассчитать это.
Обновление: поскольку Android O заставляет ваше приложение также использовать собственную оперативную память (по крайней мере, для хранения битовых карт, которая обычно является основной причиной огромного использования памяти), а не только кучу, все изменилось, и вы получите меньше OOM (потому что куча больше не содержит растровые изображения, проверьте здесь), но вы все равно должны следить за использованием памяти, если вы подозреваете, что у вас есть утечки памяти. На Android O, если у вас есть утечки памяти, которые должны были вызвать OOM на более старых версиях, кажется, что он просто потерпит крах, и вы не сможете его перехватить. Вот как проверить использование памяти:
val nativeHeapSize = Debug.getNativeHeapSize()
val nativeHeapFreeSize = Debug.getNativeHeapFreeSize()
val usedMemInBytes = nativeHeapSize - nativeHeapFreeSize
val usedMemInPercentage = usedMemInBytes * 100 / nativeHeapSize
Но я считаю, что лучше всего использовать профилировщик среды IDE, который показывает данные в режиме реального времени, используя график.
Итак, хорошая новость для Android O заключается в том, что сбои намного сложнее из-за того, что OOM хранит слишком много больших растровых изображений, но плохая новость заключается в том, что я не думаю, что можно обнаружить такой случай во время выполнения.
Вот способ рассчитать использование памяти в настоящее время запущенного приложения:
public static long getUsedMemorySize() {
long freeSize = 0L;
long totalSize = 0L;
long usedSize = -1L;
try {
Runtime info = Runtime.getRuntime();
freeSize = info.freeMemory();
totalSize = info.totalMemory();
usedSize = totalSize - freeSize;
} catch (Exception e) {
e.printStackTrace();
}
return usedSize;
}
Другой способ (в настоящее время на моем G1 отображается 25 МБ свободного места):
MemoryInfo mi = new MemoryInfo();
ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
activityManager.getMemoryInfo(mi);
long availableMegs = mi.availMem / 1048576L;
Философия управления памятью в Linux гласит: "Свободная память - пустая трата памяти".
Я предполагаю, что следующие две строки покажут, сколько памяти находится в "буферах" и сколько "кэшировано". Хотя между этими двумя понятиями есть разница (пожалуйста, не спрашивайте, что это за различие), они примерно составляют объем памяти, используемый для кэширования данных и метаданных файла.
Гораздо более полезным руководством по свободной памяти в системе Linux является free(1)
команда; на моем рабочем столе он сообщает такую информацию:
$ free -m общее количество использованных свободных общих буферов в кеше Память: 5980 1055 4924 0 91 374 -/+ буферы / кэш: 589 5391 Обмен: 6347 0 6347
Строка +/- buffers/cache: это волшебная линия, она сообщает, что у меня действительно есть около 589 мегабайт активной памяти процесса и около 5391 мегабайт "свободной" памяти, в том смысле, что 91+374 мегабайта буферов / кешируемой памяти можно выбросить, если память будет более выгодно использоваться в другом месте.
(Моя машина работала около трех часов, почти ничего не делая, кроме переполнения стека, поэтому у меня так много свободной памяти.)
Если Android не поставляется с free(1)
Вы можете сделать математику самостоятельно с /proc/meminfo
файл; Мне просто нравится free(1)
Выходной формат.:)
Я ссылаюсь на несколько работ.
ссылка:
- http://www.hanbit.co.kr/network/view.html?bi_id=1313
- Как получить общий объем оперативной памяти устройства?
Этот метод getMemorySize() возвращается MemorySize, который имеет общий и свободный объем памяти.
Я не очень верю этому коду.
Этот код тестируется на LG G3 cat.6 (v5.0.1)
private MemorySize getMemorySize() {
final Pattern PATTERN = Pattern.compile("([a-zA-Z]+):\\s*(\\d+)");
MemorySize result = new MemorySize();
String line;
try {
RandomAccessFile reader = new RandomAccessFile("/proc/meminfo", "r");
while ((line = reader.readLine()) != null) {
Matcher m = PATTERN.matcher(line);
if (m.find()) {
String name = m.group(1);
String size = m.group(2);
if (name.equalsIgnoreCase("MemTotal")) {
result.total = Long.parseLong(size);
} else if (name.equalsIgnoreCase("MemFree") || name.equalsIgnoreCase("Buffers") ||
name.equalsIgnoreCase("Cached") || name.equalsIgnoreCase("SwapFree")) {
result.free += Long.parseLong(size);
}
}
}
reader.close();
result.total *= 1024;
result.free *= 1024;
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
private static class MemorySize {
public long total = 0;
public long free = 0;
}
Я знаю, что Pattern.compile() стоит дорого, поэтому вы можете переместить его код в класс.
Я посмотрел на Android Source Tree.
Внутри com.android.server.am.ActivityManagerService.java (внутренний сервис, предоставляемый android.app.ActivityManager).
public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
final long homeAppMem = mProcessList.getMemLevel(ProcessList.HOME_APP_ADJ);
final long hiddenAppMem = mProcessList.getMemLevel(ProcessList.HIDDEN_APP_MIN_ADJ);
outInfo.availMem = Process.getFreeMemory();
outInfo.totalMem = Process.getTotalMemory();
outInfo.threshold = homeAppMem;
outInfo.lowMemory = outInfo.availMem < (homeAppMem + ((hiddenAppMem-homeAppMem)/2));
outInfo.hiddenAppThreshold = hiddenAppMem;
outInfo.secondaryServerThreshold = mProcessList.getMemLevel(
ProcessList.SERVICE_ADJ);
outInfo.visibleAppThreshold = mProcessList.getMemLevel(
ProcessList.VISIBLE_APP_ADJ);
outInfo.foregroundAppThreshold = mProcessList.getMemLevel(
ProcessList.FOREGROUND_APP_ADJ);
}
Внутри android.os.Process.java
/** @hide */
public static final native long getFreeMemory();
/** @hide */
public static final native long getTotalMemory();
Он вызывает метод JNI из android_util_Process.cpp
Заключение
MemoryInfo.availMem = MemFree + Кэшируется в /proc/meminfo.
Заметки
Общая память добавлена на уровне API 16.
/** accurate value under limitation */
int getAccurateAppUsedMemory() {
ActivityManager manager = context.getSystemService(Context.ACTIVITY_SERVICE);
Debug.MemoryInfo info = manager.getProcessMemoryInfo(new int[]{Process.myPid()})[0];
// Warning: there's a limitation of invocation frequency on Android Q or later
return info.getTotalPss(); // in kB
}
/** approximate value without limitation */
int getApproximateAppUsedMemory() {
Debug.MemoryInfo info = new Debug.MemoryInfo();
Debug.getMemoryInfo(info);
return info.getTotalPss(); // in kB
}
Вы также можете использовать инструмент DDMS, который является частью Android SDK самостоятельно. это также помогает в распределении памяти для Java-кода и нативного кода C / C++.
Вот еще один способ просмотреть использование памяти вашим приложением:
adb shell dumpsys meminfo <com.package.name> -d
Пример вывода:
Applications Memory Usage (kB):
Uptime: 2896577 Realtime: 2896577
** MEMINFO in pid 2094 [com.package.name] **
Pss Private Private Swapped Heap Heap Heap
Total Dirty Clean Dirty Size Alloc Free
------ ------ ------ ------ ------ ------ ------
Native Heap 3472 3444 0 0 5348 4605 102
Dalvik Heap 2349 2188 0 0 4640 4486 154
Dalvik Other 1560 1392 0 0
Stack 772 772 0 0
Other dev 4 0 4 0
.so mmap 2749 1040 1220 0
.jar mmap 1 0 0 0
.apk mmap 218 0 32 0
.ttf mmap 38 0 4 0
.dex mmap 3161 80 2564 0
Other mmap 9 4 0 0
Unknown 76 76 0 0
TOTAL 14409 8996 3824 0 9988 9091 256
Objects
Views: 30 ViewRootImpl: 2
AppContexts: 4 Activities: 2
Assets: 2 AssetManagers: 2
Local Binders: 17 Proxy Binders: 21
Death Recipients: 7
OpenSSL Sockets: 0
SQL
MEMORY_USED: 0
PAGECACHE_OVERFLOW: 0 MALLOC_SIZE: 0
Для общего использования памяти:
adb shell dumpsys meminfo
final long usedMemInMB=(runtime.totalMemory() - runtime.freeMemory()) / 1048576L;
final long maxHeapSizeInMB=runtime.maxMemory() / 1048576L;
final long availHeapSizeInMB = maxHeapSizeInMB - usedMemInMB;
Это странный код. Возвращает MaxMemory - (totalMemory - freeMemory). Если freeMemory равно 0, то код возвратит MaxMemory - totalMemory, так что он может быть больше или равен 0. Почему freeMemory не используется?
public static boolean isAppInLowMemory(Context context) {
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
activityManager.getMemoryInfo(memoryInfo);
return memoryInfo.lowMemory;
}