Определение размера кучи приложений в Android


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

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

9 132

9 ответов:

есть два способа подумать о вашей фразе "размер кучи приложения доступен":

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

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

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

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

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

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() цикл, поскольку они грубо смываются из памяти, пока ваше приложение elephantine принимает ванну в джакузи Android.

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

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

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

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

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

  • G1:
    • С размером кучи VM установленным к 16MB:
      • maxMemory: 16777216
      • getMemoryClass: 16
    • С размером кучи VM установленным к 24MB:
      • maxMemory: 25165824
      • getMemoryClass: 16
  • Мото Дроид:
    • С размером кучи VM установленным к 24MB:
      • maxMemory: 25165824
      • getMemoryClass: 24
    • С размером кучи VM установленным к 16MB:
      • maxMemory: 16777216
      • getMemoryClass: 24
  • Nexus One:
    • С размером кучи VM установленным к 32MB:
      • maxMemory: 33554432
      • getMemoryClass: 32
    • С размером кучи VM установленным к 24MB:
      • maxMemory: 25165824
      • getMemoryClass: 32
  • Viewsonic GTab:
    • С размером кучи ВМ установленным до 32:
      • maxMemory: 33554432
      • getMemoryClass: 32
    • С размером кучи ВМ установленным до 64:
      • maxMemory: 67108864
      • getMemoryClass: 32

в дополнение к вышесказанному, я тестировал на a Ново7 Паладин таблетки работает мороженое сэндвич. Это была по существу стоковая версия ICS, за исключением того, что я укоренил планшет через простой процесс, который не заменяет всю ОС и, в частности, не предоставляет интерфейс, который позволил бы вручную регулировать размер кучи.

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

  • Novo7
    • maxMemory: 62914560
    • getMemoryClass: 60

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

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

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

  • Samsung Galaxy Core Plus
    • maxMemory: (не указано в комментарии)
    • getMemoryClass: 48
    • largeMemoryClass: 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) большой куча
    • maxMemory: 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, как сообщалось выше.

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

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

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

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

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

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

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

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

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

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

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

чиновник API - это:

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

Debug.getNativeHeapSize() будет делать трюк, я думаю. Он был там с 1.0, хотя.

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

вот как вы это делаете:

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

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

получать, сколько кучи ваше приложение в настоящее время использует:

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

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

long availableMemory=maxMemory-usedMemory;

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

String formattedMemorySize=Formatter.formatShortFileSize(context,memorySize); 

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

Runtime.getRuntime().maxMemory()

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

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

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

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

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

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();
  }
}

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

Runtime rt = Runtime.getRuntime();
rt.maxMemory()

значение b

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

значение MB