Определить размер кучи приложения в Android - PullRequest
140 голосов
/ 13 апреля 2010

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

Я слышал, что есть функция, которая делает это в более поздних версиях SDK. В любом случае, я ищу решение, которое работает на 1.5 и выше.

Ответы [ 9 ]

438 голосов
/ 24 февраля 2012

Есть два варианта выражения «доступный размер кучи приложения»:

  1. Сколько кучи может использовать мое приложение до появления серьезной ошибки? И

  2. Сколько кучи должно использовать мое приложение, учитывая ограничения версии Android OS и аппаратного обеспечения устройства пользователя?

Существует другой метод определения каждого из вышеперечисленных.

Для пункта 1 выше: maxMemory()

, который можно вызвать (например, в методе onCreate() вашего основного вида деятельности) следующим образом:

Runtime rt = Runtime.getRuntime();
long maxMemory = rt.maxMemory();
Log.v("onCreate", "maxMemory:" + Long.toString(maxMemory));

Этот метод сообщает вам, сколько всего байтов кучи ваше приложение может использовать.

Для пункта 2 выше: getMemoryClass()

, который может быть вызван следующим образом:

ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
int memoryClass = am.getMemoryClass();
Log.v("onCreate", "memoryClass:" + Integer.toString(memoryClass));

Этот метод сообщает вам приблизительно, сколько мегабайт кучи ваше приложение должно использовать, если оно хочет надлежащим образом уважать ограничения данного устройства и права других запуск приложений без повторного принудительного включения в цикл onStop() / onResume(), поскольку они грубо вытесняются из памяти, в то время как ваше приложение-слоник принимает ванну в джакузи Android.

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

Для стандартной версии Android maxMemory() обычно возвращает примерно столько же мегабайт, сколько указано в getMemoryClass() (т. Е. Примерно в миллион раз больше последнего значения).

Единственная ситуация (о которой я знаю), для которой эти два метода могут расходиться, - это устройство на руте, работающее под управлением версии Android, такой как CyanogenMod, которая позволяет пользователю вручную выбрать размер кучи Размер должен быть разрешен для каждого приложения. Например, в CM этот параметр отображается в «Настройках CyanogenMod» / «Производительность» / «Размер кучи виртуальной машины».

ПРИМЕЧАНИЕ. ВНИМАНИЕ, ЧТО УСТАНАВЛИВАЕТ ДАННОЕ ЗНАЧЕНИЕ ВРУЧНУЮ, МОЖЕТ ОШИБИТЬ ВАШУ СИСТЕМУ, ОСОБЕННО, если вы выберите меньшее значение, чем обычно для вашего устройства.

Вот мои результаты испытаний, показывающие значения, возвращаемые maxMemory() и getMemoryClass() для четырех разных устройств, работающих под управлением CyanogenMod, с использованием двух разных (устанавливаемых вручную) значений кучи для каждого:

  • G1:
    • С размером кучи VM, установленным в 16 МБ:
      • maxMemory: 16777216
      • getMemoryClass: 16
    • Если размер кучи виртуальной машины установлен на 24 МБ:
      • maxMemory: 25165824
      • getMemoryClass: 16
  • Moto Droid:
    • Если размер кучи виртуальной машины установлен на 24 МБ:
      • maxMemory: 25165824
      • getMemoryClass: 24
    • С размером кучи VM, установленным в 16 МБ:
      • maxMemory: 16777216
      • getMemoryClass: 24
  • Nexus One:
    • Если размер кучи виртуальной машины установлен в 32 МБ:
      • maxMemory: 33554432
      • getMemoryClass: 32
    • Если размер кучи виртуальной машины установлен на 24 МБ:
      • maxMemory: 25165824
      • getMemoryClass: 32
  • Viewsonic GTab:
    • С размером кучи VM, установленным в 32:
      • maxMemory: 33554432
      • getMemoryClass: 32
    • С размером кучи VM, установленным в 64:
      • maxMemory: 67108864
      • getMemoryClass: 32

В дополнение к вышесказанному, я тестировал планшет Novo7 Paladin с Ice Cream Sandwich. По сути, это была стандартная версия ICS, за исключением того, что я проверил планшет через простой процесс, который не заменяет всю ОС, и, в частности, не предоставляет интерфейс, который позволял бы настраивать размер кучи вручную.

Для этого устройства, вот результаты:

  • Novo7
    • maxMemory: 62914560
    • getMemoryClass: 60

Также (за Кишора в комментарии ниже):

  • HTC One X
    • maxMemory: 67108864
    • getMemoryClass: 64

И (согласно комментарию Акауппи):

  • Samsung Galaxy Core Plus
    • maxMemory: (не указано в комментарии)
    • getMemoryClass: 48
    • большой класс памяти: 128

За комментарий от cmcromance:

  • Galaxy S3 (Jelly Bean) большая куча
    • maxMemory: 268435456
    • getMemoryClass: 64

И (комментарии tencent):

  • LG Nexus 5 (4.4.3) нормальный
    • maxMemory: 201326592
    • getMemoryClass: 192
  • LG Nexus 5 (4.4.3) большая куча
    • Макс. Память: 536870912
    • getMemoryClass: 192
  • Galaxy Nexus (4.3) нормальный
    • maxMemory: 100663296
    • getMemoryClass: 96
  • Galaxy Nexus (4.3) большая куча
    • maxMemory: 268435456
    • getMemoryClass: 96
  • Galaxy S4 Play Store Edition (4.4.2) обычный
    • maxMemory: 201326592
    • getMemoryClass: 192
  • Galaxy S4 Play Store Edition (4.4.2) большая куча
    • maxMemory: 536870912
    • getMemoryClass: 192

Другие устройства

  • Huawei Nexus 6P (6.0.1) нормальный
    • maxMemory: 201326592
    • getMemoryClass: 192

Я не тестировал эти два метода, используя специальный параметр android: largeHeap = "true", доступный с Honeycomb, но благодаря cmcromance и tencent у нас есть некоторые примеры значений largeHeap, как сообщалось выше.

Мое ожидание (которое, как представляется, поддерживается большими числами, указанными выше) будет означать, что этот параметр будет иметь эффект, аналогичный настройке кучи вручную через ОС с рутом - то есть он повысит значение maxMemory(), оставляя getMemoryClass() в покое. Есть еще один метод, getLargeMemoryClass (), который указывает, сколько памяти разрешено для приложения, использующего параметр largeHeap. Документация для getLargeMemoryClass () гласит: «большинству приложений не требуется такой объем памяти, и вместо этого они должны оставаться с ограничением getMemoryClass ()».

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

Обратите внимание, что класс памяти, очевидно, не должен быть кратным 8 МБ.

Из вышесказанного видно, что результат getMemoryClass() неизменен для данной конфигурации устройства / ОС, в то время как значение maxMemory () изменяется, когда пользователь настраивает кучу по-разному.

Мой собственный практический опыт заключается в том, что на G1 (который имеет класс памяти 16), если я вручную выберу 24 МБ в качестве размера кучи, я могу работать без ошибок, даже если использование моей памяти разрешено увеличиваться до 20 МБ предположительно, он может достигать 24 МБ, хотя я не пробовал этого). Но другие приложения такого же большого размера могут быть выгружены из памяти в результате скудности моего собственного приложения. И, наоборот, мое приложение может быть выгружено из памяти, если эти другие приложения с высоким уровнем обслуживания выводятся на передний план пользователем.

Таким образом, вы не можете использовать объем памяти, указанный в maxMemory(). И вы должны попытаться остаться в пределах, определенных getMemoryClass(). Одним из способов сделать это, если ничего не помогает, может быть ограничение функциональности для таких устройств таким образом, чтобы сохранить память.

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

В моем случае из соображений производительности я ограничиваю свое приложение устройствами, работающими на 2.2 и выше, и это означает, что почти все устройства, на которых запущено мое приложение, будут иметь класс памяти 24 или выше. Поэтому я могу спроектировать так, чтобы занимать до 20 МБ кучи, и уверен, что мое приложение будет хорошо работать с другими приложениями, которые пользователь может запускать одновременно.

Но всегда будет несколько пользователей с правами root, которые загрузили версию Android 2.2 или выше на старое устройство (например, G1). Когда вы сталкиваетесь с такой конфигурацией, в идеале вам следует сократить использование памяти, даже если maxMemory() говорит вам, что вы можете пойти намного выше, чем 16 МБ, которые getMemoryClass() говорит вам, что должен быть целью. И если вы не можете надежно убедиться, что ваше приложение будет в пределах этого бюджета, то по крайней мере убедитесь, что onStop() / onResume() работает без проблем.

getMemoryClass(), как указано выше Дианой Хэкборн (hackbod), доступно только для уровня API 5 (Android 2.0), и поэтому, как она советует, можно предположить, что физическое оборудование любого устройства, работающего ранее Версия ОС предназначена для оптимальной поддержки приложений, занимающих пространство кучи не более 16 МБ.

В отличие от этого, maxMemory(), согласно документации, доступен вплоть до уровня API 1. maxMemory() в версии до 2.0, вероятно, вернет значение 16 МБ, но я сделаю обратите внимание, что в моих (гораздо более поздних) версиях CyanogenMod пользователь может выбрать значение кучи, равное 12 МБ, что, вероятно, приведет к более низкому пределу кучи, и поэтому я предлагаю продолжить тестирование значения maxMemory() даже для версий ОС до 2.0. Возможно, вам даже придется отказаться от запуска в маловероятном случае, если это значение установлено даже ниже 16 МБ, если вам нужно, чтобы значение было больше, чем maxMemory(), разрешено.

20 голосов
/ 14 апреля 2010

Официальный API :

Это было введено в 2.0, где появились большие устройства памяти. Можно предположить, что устройства под управлением предыдущих версий ОС используют исходный класс памяти (16).

13 голосов
/ 14 марта 2016

Вот как это делается:

Получение максимального размера кучи, который может использовать приложение:

Runtime runtime = Runtime.getRuntime();
long maxMemory=runtime.maxMemory();

Получение объема кучи, используемого вашим приложением:

long usedMemory=runtime.totalMemory() - runtime.freeMemory();

Получение информации о том, сколько кучи теперь может использовать ваше приложение (доступная память):

long availableMemory=maxMemory-usedMemory;

И, чтобы красиво отформатировать каждый из них, вы можете использовать:

String formattedMemorySize=Formatter.formatShortFileSize(context,memorySize); 
13 голосов
/ 14 апреля 2010

Debug.getNativeHeapSize() добьется цели, я думаю. Это было там с 1.0, хотя.

Класс Debug имеет множество отличных методов для отслеживания выделения ресурсов и других проблем с производительностью. Кроме того, если вам нужно обнаружить ситуацию с нехваткой памяти, проверьте Activity.onLowMemory().

4 голосов
/ 24 апреля 2011

Возвращает максимальный размер кучи в байтах:

Runtime.getRuntime().maxMemory()

Я использовал ActivityManager.getMemoryClass (), но в CyanogenMod 7 (я не проверял его в других местах) он возвращает неправильное значение, если пользователь устанавливает размер кучи вручную.

2 голосов
/ 20 июня 2017

Некоторые операции выполняются быстрее, чем менеджер пространства кучи Java. Задержка операций на некоторое время может освободить место в памяти. Вы можете использовать этот метод, чтобы избежать ошибки размера кучи:

waitForGarbageCollector(new Runnable() {
  @Override
  public void run() {

    // Your operations.
  }
});

/**
 * Measure used memory and give garbage collector time to free up some
 * space.
 *
 * @param callback Callback operations to be done when memory is free.
 */
public static void waitForGarbageCollector(final Runnable callback) {

  Runtime runtime;
  long maxMemory;
  long usedMemory;
  double availableMemoryPercentage = 1.0;
  final double MIN_AVAILABLE_MEMORY_PERCENTAGE = 0.1;
  final int DELAY_TIME = 5 * 1000;

  runtime =
    Runtime.getRuntime();

  maxMemory =
    runtime.maxMemory();

  usedMemory =
    runtime.totalMemory() -
    runtime.freeMemory();

  availableMemoryPercentage =
    1 -
    (double) usedMemory /
    maxMemory;

  if (availableMemoryPercentage < MIN_AVAILABLE_MEMORY_PERCENTAGE) {

    try {
      Thread.sleep(DELAY_TIME);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }

    waitForGarbageCollector(
      callback);
  } else {

    // Memory resources are availavle, go to next operation:

    callback.run();
  }
}
1 голос
/ 03 февраля 2014

Asus Nexus 7 (2013) 32Gig: getMemoryClass () = 192 maxMemory () = 201326592

Я сделал ошибку, прототипировав мою игру на Nexus 7, а затем обнаружил, что почти сразу же не хватило памяти на обычном планшете моей жены 4.04 (класс памяти 48, maxmemory 50331648)

Мне нужно будет реструктурировать свой проект, чтобы загружать меньше ресурсов, когда я определю, что класс памяти мал.
Есть ли способ в Java, чтобы увидеть текущий размер кучи? (Я вижу это ясно в logCat при отладке, но мне бы хотелось, чтобы это можно было увидеть в коде для адаптации, например, если currentheap> (maxmemory / 2) выгружает высококачественные растровые изображения загружает низкое качество

0 голосов
/ 04 сентября 2013
Runtime rt = Runtime.getRuntime();
rt.maxMemory()

значение b

ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
am.getMemoryClass()

значение - МБ

0 голосов
/ 13 апреля 2010

Вы имеете в виду программно или просто во время разработки и отладки? Если последнее, вы можете увидеть эту информацию с точки зрения DDMS в Eclipse. Когда ваш эмулятор (возможно, даже физический телефон, который подключен) работает, он выведет список активных процессов в окне слева. Вы можете выбрать его, и есть возможность отслеживать распределение кучи.

...