Обратите внимание, что использование памяти в современных операционных системах, таких как Linux, является чрезвычайно сложной и трудной для понимания областью. На самом деле шансы на то, что вы на самом деле правильно интерпретируете полученные вами цифры, крайне низки. (Практически каждый раз, когда я смотрю на цифры использования памяти с другими инженерами, всегда идет долгая дискуссия о том, что они на самом деле означают, что приводит только к неопределенному выводу.)
Примечание: теперь у нас есть гораздо более обширная документация по Управление памятью вашего приложения , которая охватывает большую часть материала здесь и более соответствует состоянию Android.
Прежде всего, возможно, стоит прочитать последнюю часть этой статьи, в которой обсуждается, как управлять памятью на Android:
Изменения API службы, начиная с Android 2.0
Теперь ActivityManager.getMemoryInfo()
- это наш API верхнего уровня для оценки общего использования памяти. В основном это делается для того, чтобы помочь приложению определить, насколько близко система перестает иметь память для фоновых процессов, и, таким образом, нужно начинать убивать необходимые процессы, такие как службы. Для приложений на чистом Java это должно быть бесполезно, поскольку ограничение кучи Java отчасти позволяет избежать того, чтобы одно приложение могло нагружать систему до этого уровня.
Переходя на более низкий уровень, вы можете использовать API отладки для получения необработанной информации уровня памяти об использовании памяти: 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), и это еще менее понятно.
Таким образом, если бы вы взяли все физическое ОЗУ, фактически сопоставленное каждому процессу, и суммировали все процессы, вы, вероятно, в конечном итоге получили бы число, намного превышающее фактическое общее ОЗУ.
Число Pss
- это показатель, вычисляемый ядром, который учитывает совместное использование памяти - в основном, каждая страница ОЗУ в процессе масштабируется в соответствии с количеством других процессов, также использующих эту страницу. Таким образом, вы можете (теоретически) сложить 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
- 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 out of memory killer настроен для конкретной системы, чтобы гарантировать, что фоновые процессы будут убиты до того, как кэшированная оперативная память израсходует ими слишком много, чтобы привести к такой подкачке.