Как узнать использование памяти моего приложения в Android?

Как я могу найти память, используемую в приложении для Android, программно?

Я надеюсь, что есть способ сделать это. Кроме того, как мне получить бесплатную память телефона?

Обратите внимание, что использование памяти в современных операционных системах, таких как Linux, является чрезвычайно сложной и трудно понятной областью. На самом деле шансы на то, что вы действительно правильно интерпретируете все, что вы получаете, крайне низки. (Практически каждый раз, когда я смотрю на номера использования памяти с другими инженерами, всегда есть длинная дискуссия о том, что они на самом деле означают, что только приводит к неопределенному выводу).

Примечание. Теперь у нас есть гораздо более обширная документация по управлению памятью вашего приложения, которая охватывает большую часть материала здесь и более современна с состоянием Android.

Прежде всего, вероятно, прочитайте последнюю часть этой статьи, в которой обсуждается, как управляется память на Android:

Изменения API сервисов, начиная с Android 2.0

Теперь ActivityManager.getMemoryInfo() – это наш API самого высокого уровня для просмотра общего использования памяти. В основном это помогает определить, насколько близко система приближается к отсутствию памяти для фоновых процессов, поэтому необходимо начать убивать необходимые процессы, такие как службы. Для чистых приложений Java это должно быть малопригодно, так как ограничение кучи Java частично отчасти позволяет избежать того, что одно приложение не сможет подчеркнуть систему до этого момента.

Находясь на более низком уровне, вы можете использовать API Debug для получения информации об уровне памяти на уровне ядра: android.os.Debug.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-системах в целом) фактически разделяется между несколькими процессами. Итак, сколько памяти использует процесс, на самом деле неясно. Добавьте поверх этого пейджинга на диск (не говоря уже об обмене, который мы не используем на Android), и это еще менее понятно.

Таким образом, если вы должны были отобрать всю физическую RAM, фактически отображаемую для каждого процесса, и добавить все процессы, вы, вероятно, в конечном итоге получите число, намного большее, чем фактическая общая оперативная память.

Номер Pss – это метрика, которую вычисляет kernel, которое учитывает совместное использование памяти – в основном каждая страница ОЗУ в процессе масштабируется соотношением количества других процессов, также использующих эту страницу. Таким образом, вы можете (теоретически) добавить pss во все процессы, чтобы увидеть общую RAM, которую они используют, и сравнить pss между процессами, чтобы получить приблизительное представление об их относительном весе.

Другим интересным показателем здесь является PrivateDirty , который в основном представляет собой объем оперативной памяти внутри процесса, который нельзя выгружать на диск (он не поддерживается одними и теми же данными на диске) и не используется совместно с другими процессами. Другой способ взглянуть на это – это ОЗУ, которое станет доступным системе, когда этот процесс уйдет (и, вероятно, быстро включится в кеши и другие его применения).

Для этого это API SDK. Однако вы можете делать это как разработчик с вашего устройства.

Используя adb , есть много информации, которую вы можете получить о работе используемой системы памяти. Обычной является команда adb shell dumpsys meminfo которая выплевывает кучу информации об использовании памяти в каждом процессе Java, содержащей вышеуказанную информацию, а также множество других вещей. Вы также можете использовать имя или pid одного процесса для просмотра, например, система adb shell dumpsys meminfo system дает мне системный процесс:

 ** MEMINFO в pid 890 [система] **
                     родной далвик другой всего
             размер: 10940 7047 не определено 17987
        выделено: 8943 5516 не определено 14459
             бесплатно: 336 1531 не определено 1867
            (Pss): 4585 9282 11916 25783
   (общий грязный): 2184 3596 916 6696
     (пассивный): 4504 5956 7456 17916

  Объекты
            Просмотров: 149 ViewRoots: 4
      AppContexts: 13 Деятельность: 0
           Активы: 4 Менеджеры по управлению активами: 4
    Локальные привязки: 141 прокси-связки: 158
 Получатели смерти: 49
  Разъемы OpenSSL: 0

  SQL
             heap: 205 dbFiles: 0
        numPagers: 0 inactivePageKB: 0
     Активный участник: 0

Верхний раздел является основным, где size – это общий размер в адресном пространстве конкретной кучи, allocated – kb фактических распределений, которые куча думает, что он имеет, free – оставшаяся kb, свободная куча для дополнительных распределений, и 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 / система / bin / installd
    60 396K 392K 93K 84K / system / bin / keystore
    51 280K 276K 74K 68K / система / bin / servicemanager
    54 256K 252K 69K 64K / система / bin / debuggerd

Здесь столбцы Vss и Rss в основном представляют собой шум (это прямое адресное пространство и использование ОЗУ в процессе, где, если вы добавляете использование ОЗУ в процессы, вы получаете смехотворно большое количество).

Pss , как мы видели раньше, и Uss Priv Dirty .

Интересно отметить здесь: Pss и Uss немного (или несколько больше) отличаются от того, что мы видели в meminfo . Почему это? Ну procrank использует другой механизм ядра для сбора своих данных, чем meminfo , и они дают несколько разные результаты. Почему это? Честно говоря, я понятия не имею. Я считаю, что procrank может быть более точным … но на самом деле это просто оставляет точку зрения: «Возьмите любую информацию о памяти, которую вы получите с солью, часто очень крупным зерном».

Наконец, есть команда adb shell cat /proc/meminfo которая дает краткое описание общего использования памяти в системе. Здесь много данных, только первые несколько номеров, о которых стоит поговорить (а остальные из них понятны нескольким людям, и мои вопросы о тех немногих людей о них часто приводят к противоречивым объяснениям):

 MemTotal: 395144 kB
 MemFree: 184936 kB
 Буферы: 880 кБ
 Кэшировано: 84104 кБ
 SwapCached: 0 kB

MemTotal – это общий объем памяти, ansible ядру и пользовательскому пространству (часто меньше, чем фактическое физическое ОЗУ устройства, так как некоторые из этих ОЗУ необходимы для радио, буферов 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 runningAppProcesses = activityManager.getRunningAppProcesses(); Map pidMap = new TreeMap(); for (RunningAppProcessInfo runningAppProcessInfo : runningAppProcesses) { pidMap.put(runningAppProcessInfo.pid, runningAppProcessInfo.processName); } Collection 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.os.Debug.MemoryInfo, но ни один из этих объектов не говорит вам, с какими связями они связаны. Если вы просто передадите массив всех pids, вы не сможете понять результаты. Насколько я понимаю, это использование, это делает бессмысленным передавать более чем за один pid за раз, а затем, если это так, зачем делать так, чтобы ActivityManager.getProcessMemoryInfo () принимал только массив int?

Hackbod является одним из лучших ответов на переполнение стека. Он проливает свет на очень неясную тему. Это мне очень помогло.

Еще один действительно полезный ресурс – это обязательное видео: Google I / O 2011: управление памятью для Android-приложений


ОБНОВИТЬ:

Статистика процесса, служба, чтобы узнать, как ваше приложение управляет памятью, объяснено в сообщении в блоге. Статистика процесса: понимание того, как ваше приложение использует RAM от Dianne Hackborn:

Android Studio 0.8.10+ представила невероятно полезный инструмент под названием Memory Monitor .

введите описание изображения здесь

Что это хорошо для:

  • Отображение доступной и используемой памяти на графике и события сбора мусора с течением времени.
  • Быстрое тестирование на медленность приложения может быть связано с чрезмерными событиями сбора мусора.
  • Быстрое тестирование сбоев приложений может быть связано с нехваткой памяти.

введите описание изображения здесь

Рисунок 1. Принуждение события GC (assembly мусора) на Android Memory Monitor

Используя это, вы можете получить много полезной информации о потреблении оперативной памяти вашего приложения в режиме реального времени.

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() – выполняет работу, но она слишком медленная. Он занимает около 200 мс на 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 . Вы можете найти более подробную информацию об этом здесь: один , два и три .


PS Я заметил, что в теме по-прежнему отсутствует фактический и простой fragment кода, как оценить использование частной памяти в частной памяти, если производительность не является критическим требованием:

 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-х дней получения и исследования инструментов памяти adb) я думаю, что смогу помочь и в моем мнении .

Как говорит Хакбод: Таким образом, если вы должны были отобрать всю физическую RAM, фактически отображаемую в каждом процессе, и добавить все процессы, вы, вероятно, в конечном итоге получите число, намного большее, чем фактическое суммарное ОЗУ. так что вы не можете получить точный объем памяти за процесс.

Но вы можете приблизиться к нему какой-то логикой … и я расскажу, как ..

Есть некоторые API, такие как android.os.Debug.MemoryInfo и ActivityManager.getMemoryInfo() упомянутые выше, которые вы уже, возможно, читали и использовали, но я буду говорить о другом пути

Итак, во-первых, вы должны быть пользователем root, чтобы заставить его работать. Войдите в консоль с правами root, выполнив su в процессе и получив свой output and input stream . Затем передайте id\n (введите) в ouputstream и напишите его для обработки вывода. If получит входной stream, содержащий uid=0 , вы являетесь пользователем root.

Теперь вот логика, которую вы будете использовать в описанном выше процессе

Когда вы получаете выход из процесса, пропустите команду (procrank, dumpsys meminfo и т. Д.) С \n вместо id и получите свой inputstream stream и прочитайте, сохраните stream в байтах [], char [] и т. Д. Используйте необработанные данные. . и ты закончил !!!!!

разрешение:

  

Проверьте, являетесь ли вы пользователем 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(); } } 

logcat: результат

Вы получаете необработанные данные в одной строке с консоли, а не в каком-либо экземпляре из любого API, который сложно хранить, поскольку вам нужно будет отделить его вручную .

Это просто попытка, пожалуйста, предложите мне, если я что-то пропустил

  • java.lang.ClassCastException
  • Обновление Eclipse с помощью средств разработки Android v. 23
  • onInterceptTouchEvent получает только ACTION_DOWN
  • Java: вызов метода внешнего classа в анонимном внутреннем classе
  • Какова максимальная глубина стека вызовов java?
  • Как сохранять cookie при использовании HTTPUrlConnection?
  • Проверить навигационную панель
  • Get Cell Tower Locations - Android
  • как разобрать JSONArray в android
  • String.replaceAll без RegEx
  • Преобразование UTC в текущее время локали
  • Interesting Posts

    Почему мой выход opengl отличается для разных устройств?

    Объединить строки Excel с двух листов

    C #: предварительная подготовка к началу файла

    C # WebBrowser Control – отправка формы не работает с помощью InvokeMember («Click»)

    Как извлечь сборку из GAC?

    Что такое исключение NoSuchBeanDefinitionException и как его исправить?

    findViewById () возвращает null, когда я вызываю его в onCreate ()

    Устройство ADB для Android запрещено

    Android: прослушиватель изменений в подключении к Интернету

    Предупреждение Google: ресурс, интерпретируемый как шрифт, но переданный с помощью приложения типа MIME / октетного streamа

    Команды вызова WPF через события

    C ++ HTML-шаблон, библиотека шаблонов, библиотека генераторов HTML

    Изменение шрифтов адресных баров и поисковых систем в Firefox3.6?

    Entity Framework 6 GUID как первичный ключ: не может вставить значение NULL в столбец «Id», таблицу «FileStore»; столбец не допускает

    C ++ 11: массив времени компиляции с логарифмической глубиной оценки

    Давайте будем гением компьютера.