Как обнаружить использование памяти моего приложения в Android?
Как я могу найти память, используемую в моем приложении Android, программно?
Я надеюсь, что есть способ сделать это. Кроме того, как я могу получить свободную память телефона?
8 ответов
обратите внимание, что использование памяти в современных операционных системах, как Linux-это очень сложная и трудная для понимания область. На самом деле шансы на то, что вы действительно правильно интерпретируете любые цифры, которые вы получаете, чрезвычайно низки. (Почти каждый раз, когда я смотрю на цифры использования памяти с другими инженерами, всегда идет долгая дискуссия о том, что они на самом деле означают, что приводит только к неясным выводам.)
Примечание: теперь у нас гораздо больше обширная документация по управление памятью вашего приложения это охватывает большую часть материала здесь и является более современным с состоянием Android.
во-первых, вероятно, прочитать последнюю часть этой статьи, которая имеет некоторое обсуждение того, как память управляется на Android:
изменения API службы, начиная с Android 2.0
теперь ActivityManager.getMemoryInfo()
наш API самого высокого уровня для просмотра общего использования памяти. Это в основном, чтобы помочь приложению оценить, насколько близка система к тому, чтобы не иметь больше памяти для фоновых процессов, поэтому необходимо начать убивать необходимые процессы, такие как службы. Для чистых приложений Java это должно быть мало пользы, так как ограничение кучи Java существует частично, чтобы избежать одного приложения от возможности подчеркнуть систему до этого момента.
переходя на более низкий уровень, вы можете использовать API отладки для получения необработанной информации об использовании памяти на уровне ядра: android.ОС.Отлаживать.MemoryInfo
Примечание начиная с 2.0 существует также API,ActivityManager.getProcessMemoryInfo
, чтобы получить эту информацию о другом процессе: ActivityManager.getProcessMemoryInfo (int[])
это возвращает низкоуровневую структуру MemoryInfo со всеми этими данными:
/** The proportional set size for dalvik. */
public int dalvikPss;
/** The private dirty pages used by dalvik. */
public int dalvikPrivateDirty;
/** The shared dirty pages used by dalvik. */
public int dalvikSharedDirty;
/** The proportional set size for the native heap. */
public int nativePss;
/** The private dirty pages used by the native heap. */
public int nativePrivateDirty;
/** The shared dirty pages used by the native heap. */
public int nativeSharedDirty;
/** The proportional set size for everything else. */
public int otherPss;
/** The private dirty pages used by everything else. */
public int otherPrivateDirty;
/** The shared dirty pages used by everything else. */
public int otherSharedDirty;
а в чем разница между Pss
, PrivateDirty
и SharedDirty
... Ну вот и начинается самое интересное.
много памяти в Android (и Linux в целом) фактически совместно использоваться несколькими процессами. Так что, сколько памяти использует процесс, на самом деле не ясно. Добавьте поверх этого подкачки на диск (не говоря уже о swap, который мы не используем на Android), и это еще менее ясно.
на Pss
number-это метрика, которую вычисляет ядро, учитывающая общий доступ к памяти - в основном каждая страница ОЗУ в процессе масштабируется отношением числа других процессов, также использующих эту страницу. Таким образом, вы можете (теоретически) сложить pss во всех процессах, чтобы увидеть общую ОЗУ, которую они используют, и сравнить pss между процессами, чтобы получить приблизительное представление об их относительном весе.
другой интересной метрикой здесь является PrivateDirty
, что в основном является количеством ОЗУ внутри процесс, который не может быть выгружен на диск (он не поддерживается теми же данными на диске) и не используется совместно с другими процессами. Другой способ взглянуть на это-ОЗУ, которое станет доступным для системы, когда этот процесс исчезнет (и, вероятно, быстро попадет в кэши и другие его использования).
это в значительной степени API SDK для этого. Однако есть больше, что вы можете сделать в качестве разработчика с вашим устройством.
используя adb
, есть много информации вы можете узнать об использовании памяти работающей системы. Общим является команда adb shell dumpsys meminfo
который выплюнет кучу информации об использовании памяти каждого процесса Java, содержащего вышеуказанную информацию, а также множество других вещей. Вы также можете указать имя или pid одного процесса, чтобы увидеть, например adb shell dumpsys meminfo system
дайте мне системный процесс:
** MEMINFO in pid 890 [system] ** native dalvik other total size: 10940 7047 N/A 17987 allocated: 8943 5516 N/A 14459 free: 336 1531 N/A 1867 (Pss): 4585 9282 11916 25783 (shared dirty): 2184 3596 916 6696 (priv dirty): 4504 5956 7456 17916 Objects Views: 149 ViewRoots: 4 AppContexts: 13 Activities: 0 Assets: 4 AssetManagers: 4 Local Binders: 141 Proxy Binders: 158 Death Recipients: 49 OpenSSL Sockets: 0 SQL heap: 205 dbFiles: 0 numPagers: 0 inactivePageKB: 0 activePageKB: 0
верхний раздел является основным, где size
- общий размер адресного пространства конкретной кучи, allocated
- это КБ фактических распределений, которые куча думает, что она имеет,free
является ли оставшийся КБ свободным, куча имеет для дополнительных распределений, и pss
и priv dirty
то же самое, что обсуждалось ранее для конкретных страниц, связанных с каждой из куч.
если вы просто хотите посмотреть на использование памяти для всех процессов, вы можете использовать команду adb shell procrank
. Вывод этого в той же системе выглядит так:
PID Vss Rss Pss Uss cmdline 890 84456K 48668K 25850K 21284K system_server 1231 50748K 39088K 17587K 13792K com.android.launcher2 947 34488K 28528K 10834K 9308K com.android.wallpaper 987 26964K 26956K 8751K 7308K com.google.process.gapps 954 24300K 24296K 6249K 4824K com.android.phone 948 23020K 23016K 5864K 4748K com.android.inputmethod.latin 888 25728K 25724K 5774K 3668K zygote 977 24100K 24096K 5667K 4340K android.process.acore ... 59 336K 332K 99K 92K /system/bin/installd 60 396K 392K 93K 84K /system/bin/keystore 51 280K 276K 74K 68K /system/bin/servicemanager 54 256K 252K 69K 64K /system/bin/debuggerdна
Vss
и Rss
столбцы в основном шум (это прямое адресное пространство и использование ОЗУ процесса, где, если вы добавите использование ОЗУ между процессами, вы получите смехотворно большое количество).
Pss
как мы видели раньше, и Uss
is Priv Dirty
.
интересная вещь, чтобы отметить здесь: Pss
и Uss
немного (или больше чем немного) отличается от того, что мы видели в meminfo
. Почему так? Ну procrank использует другой механизм ядра для сбора данных чем meminfo
делает, а они дают немного разные результаты. Почему так? Честно говоря, понятия не имею. Я верю procrank
может быть более точным... но на самом деле, это просто оставить точку: "возьмите любую информацию памяти вы получаете с солью; часто очень большое зерно."
наконец-то есть команда adb shell cat /proc/meminfo
это дает резюме общего использования памяти системы. Здесь много данных, только первые несколько чисел, которые стоит обсудить (и остальные понимали немногие люди, и мои вопросы этих немногих людей о них часто приводили к противоречивым объяснениям):
MemTotal: 395144 kB MemFree: 184936 kB Buffers: 880 kB Cached: 84104 kB SwapCached: 0 kB
MemTotal
- общий объем памяти, доступный ядру и пользовательскому пространству (часто меньше, чем фактическая физическая ОЗУ устройства, так как часть этой ОЗУ необходима для радио, буферов DMA и т. д.).
MemFree
- это количество ОЗУ, которое вообще не используется. Число, которое вы видите здесь, очень велико; как правило, на Android система это будет всего несколько МБ, так как мы стараемся использовать доступную память для запуска процессов
Cached
используется ли ОЗУ для кэширования файловой системы и других подобных вещей. Типичные системы должны будут иметь 20 Мб или около того для этого, чтобы избежать попадания в плохие состояния подкачки; убийца Android из памяти настроен для конкретной системы, чтобы убедиться, что фоновые процессы убиты, прежде чем кэшированная оперативная память потребляется слишком много ими, чтобы привести к такой подкачки.
Да, вы можете получить информацию о памяти программно и решить, следует ли выполнять интенсивную работу с памятью.
получить размер кучи VM, позвонив:
Runtime.getRuntime().totalMemory();
получить выделенную память VM, позвонив:
Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
получить ограничение размера кучи VM, позвонив:
Runtime.getRuntime().maxMemory()
получить собственную выделенную память, вызвав:
Debug.getNativeHeapAllocatedSize();
Я сделал приложение, чтобы выяснить поведение OutOfMemoryError и контролировать память использование.
https://play.google.com/store/apps/details?id=net.coocood.oomresearch
вы можете получить исходный код по https://github.com/coocood/oom-research
это незавершенная работа, но вот чего я не понимаю:
ActivityManager activityManager = (ActivityManager) context.getSystemService(ACTIVITY_SERVICE);
MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
activityManager.getMemoryInfo(memoryInfo);
Log.i(TAG, " memoryInfo.availMem " + memoryInfo.availMem + "\n" );
Log.i(TAG, " memoryInfo.lowMemory " + memoryInfo.lowMemory + "\n" );
Log.i(TAG, " memoryInfo.threshold " + memoryInfo.threshold + "\n" );
List<RunningAppProcessInfo> runningAppProcesses = activityManager.getRunningAppProcesses();
Map<Integer, String> pidMap = new TreeMap<Integer, String>();
for (RunningAppProcessInfo runningAppProcessInfo : runningAppProcesses)
{
pidMap.put(runningAppProcessInfo.pid, runningAppProcessInfo.processName);
}
Collection<Integer> keys = pidMap.keySet();
for(int key : keys)
{
int pids[] = new int[1];
pids[0] = key;
android.os.Debug.MemoryInfo[] memoryInfoArray = activityManager.getProcessMemoryInfo(pids);
for(android.os.Debug.MemoryInfo pidMemoryInfo: memoryInfoArray)
{
Log.i(TAG, String.format("** MEMINFO in pid %d [%s] **\n",pids[0],pidMap.get(pids[0])));
Log.i(TAG, " pidMemoryInfo.getTotalPrivateDirty(): " + pidMemoryInfo.getTotalPrivateDirty() + "\n");
Log.i(TAG, " pidMemoryInfo.getTotalPss(): " + pidMemoryInfo.getTotalPss() + "\n");
Log.i(TAG, " pidMemoryInfo.getTotalSharedDirty(): " + pidMemoryInfo.getTotalSharedDirty() + "\n");
}
}
почему PID не сопоставлен с результатом в activityManager.getProcessMemoryInfo()? Очевидно, что вы хотите сделать полученные данные значимыми, так почему Google так сложно сопоставить результаты? Текущая система даже не работает хорошо, если я хочу обработать все использование памяти, так как возвращаемый результат представляет собой массив android.ОС.Отлаживать.MemoryInfo объекты, но ни один из этих объектов на самом деле сказать вам, что pids они связаны С. Если вы просто передадите массив всех PID, у вас не будет возможности понять результаты. Как я понимаю, это использование, это делает бессмысленным передавать более одного pid за раз, а затем, если это так, зачем делать это так, что activityManager.getProcessMemoryInfo() принимает только массив int?
Hackbod является одним из лучших ответов на переполнение стека. Это проливает свет на очень темную тему. Это мне очень помогло.
еще один действительно полезный ресурс-это обязательное видео:Google I / O 2011: управление памятью для приложений Android
обновление:
статистика процесса, сервис, чтобы узнать, как ваше приложение управляет памятью, объясненной в блогеСтатистика Процесса: Понимание Того, Как Ваше Приложение Использует Рам!--4--> по Диана Hackborn:
Android Studio 0.8.10 + представила невероятно полезный инструмент под названием Монитор Памяти.
Что это хорошо для:
- отображение доступной и используемой памяти в графике и сборке мусора события с течением времени.
- быстрое тестирование медлительности приложения может быть связано с избыточными событиями сбора мусора.
- быстро испытания ли приложение может быть связано с нехваткой памяти.
Рис. 1. Форсирование события GC (сбор мусора) на мониторе памяти Android
вы можете иметь много хорошей информации о RAM вашего приложения в режиме реального времени, используя его.
1) я думаю, нет, по крайней мере, не от Java.
2)
ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
MemoryInfo mi = new MemoryInfo();
activityManager.getMemoryInfo(mi);
Log.i("memory free", "" + mi.availMem);
мы выяснили, что все стандартные способы получения общей памяти текущего процесса есть некоторые проблемы.
-
Runtime.getRuntime().totalMemory()
: возвращает только память JVM -
ActivityManager.getMemoryInfo()
,Process.getFreeMemory()
и все остальное, на основе/proc/meminfo
- возвращает информацию о памяти обо всех объединенных процессах (например,android_util_Process.cpp) -
Debug.getNativeHeapAllocatedSize()
- используетmallinfo()
которые возвращают информацию о выделениях памяти, выполняемыхmalloc()
и только связанные функции (см. android_os_Debug.cpp) -
Debug.getMemoryInfo()
- делает работу, но это слишком медленно. Это занимает около 200ms on Nexus 6 для одного вызова. Накладные расходы на производительность делают эту функцию бесполезной для нас, поскольку мы называем ее регулярно, и каждый вызов довольно заметен (см. android_os_Debug.cpp) -
ActivityManager.getProcessMemoryInfo(int[])
звонкиDebug.getMemoryInfo()
внутри (см. ActivityManagerService.java)
наконец, мы закончили использовать следующий код:
const long pageSize = 4 * 1024; //`sysconf(_SC_PAGESIZE)`
string stats = File.ReadAllText("/proc/self/statm");
var statsArr = stats.Split(new [] {' ', '\t', '\n'}, 3);
if( statsArr.Length < 2 )
throw new Exception("Parsing error of /proc/self/statm: " + stats);
return long.Parse(statsArr[1]) * pageSize;
возвращает VmRSS метрика. Подробнее об этом вы можете узнать здесь:один, два и три.
П. С. я заметил, что тема по-прежнему имеет отсутствие фактического и простого фрагмента кода о том, как оценка использование памяти процесса, если производительность не является критическим требованием:
Debug.MemoryInfo memInfo = new Debug.MemoryInfo();
Debug.getMemoryInfo(memInfo);
long res = memInfo.getTotalPrivateDirty();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
res += memInfo.getTotalPrivateClean();
return res * 1024L;
есть много ответов выше, которые, безусловно, помогут вам, но (после 2 дней позволять и исследования на инструментах памяти АБР) я думаю, что могу помочь с моим мнение тоже.
As Hackbod говорит : так есть невозможно получить точный объем памяти для каждого процесса.
но вы можете приблизиться к нему по какой-то логике..и я расскажу как..
есть некоторые API, такие как
android.os.Debug.MemoryInfo
иActivityManager.getMemoryInfo()
упомянутый выше, о котором вы уже, возможно, читали и использовали, но я буду говорить о другом способе
поэтому сначала вам нужно быть пользователем root, чтобы заставить его работать. Войдите в консоль с привилегией root, выполнив su
в процессе и получить его output and input stream
. Тогда пас id\n
(enter) в ouputstream и напишите его для обработки вывода, Если получите inputstream, содержащий uid=0
, вы пользователь root.
теперь вот логика, которую вы будете использовать в вышеуказанном процессе
когда вы получаете ouputstream процесса передать вам команду (procrank, dumpsys meminfo и т. д...) с \n
вместо id и inputstream
и прочитайте, сохраните поток в байтах[ ], char[ ] etc.. использовать raw данные..и вы закончили!!!!!
разрешение :
<uses-permission android:name="android.permission.FACTORY_TEST"/>
Проверьте, являетесь ли вы пользователем root:
// su command to get root access
Process process = Runtime.getRuntime().exec("su");
DataOutputStream dataOutputStream =
new DataOutputStream(process.getOutputStream());
DataInputStream dataInputStream =
new DataInputStream(process.getInputStream());
if (dataInputStream != null && dataOutputStream != null) {
// write id to console with enter
dataOutputStream.writeBytes("id\n");
dataOutputStream.flush();
String Uid = dataInputStream.readLine();
// read output and check if uid is there
if (Uid.contains("uid=0")) {
// you are root user
}
}
выполнить команду su
Process process = Runtime.getRuntime().exec("su");
DataOutputStream dataOutputStream =
new DataOutputStream(process.getOutputStream());
if (dataOutputStream != null) {
// adb command
dataOutputStream.writeBytes("procrank\n");
dataOutputStream.flush();
BufferedInputStream bufferedInputStream =
new BufferedInputStream(process.getInputStream());
// this is important as it takes times to return to next line so wait
// else you with get empty bytes in buffered stream
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// read buffered stream into byte,char etc.
byte[] bff = new byte[bufferedInputStream.available()];
bufferedInputStream.read(bff);
bufferedInputStream.close();
}
}
вы получаете необработанные данные в одной строке из консоли, а не в каком-либо экземпляре из любого API, который сложно хранить, поскольку вам нужно будет отделить его вручную.
это просто попытка, пожалуйста, предложите мне, если я что-то пропустил