Вопрос

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

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

Это было полезно?

Решение

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

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

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

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

Для пункта 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, используя для каждого два разных (установленных вручную) значения кучи:

  • Г1:
    • Если размер кучи виртуальной машины установлен на 16 МБ:
      • МаксПамять:16777216
      • получитьМемориКласс:16
    • Если размер кучи виртуальной машины установлен на 24 МБ:
      • МаксПамять:25165824
      • получитьМемориКласс:16
  • Мотодроид:
    • Если размер кучи виртуальной машины установлен на 24 МБ:
      • МаксПамять:25165824
      • получитьМемориКласс:24
    • Если размер кучи виртуальной машины установлен на 16 МБ:
      • МаксПамять:16777216
      • получитьМемориКласс:24
  • Нексус Один:
    • Если размер кучи виртуальной машины установлен на 32 МБ:
      • МаксПамять:33554432
      • получитьМемориКласс:32
    • Если размер кучи виртуальной машины установлен на 24 МБ:
      • МаксПамять:25165824
      • получитьМемориКласс:32
  • Viewsonic GTab:
    • Если размер кучи виртуальной машины установлен на 32:
      • МаксПамять:33554432
      • получитьМемориКласс:32
    • Если размер кучи виртуальной машины установлен на 64:
      • МаксПамять:67108864
      • получитьМемориКласс:32

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

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

  • Ново7
    • МаксПамять:62914560
    • получитьМемориКласс:60

Также (согласно Кишору в комментарии ниже):

  • HTC One X
    • МаксПамять:67108864
    • получитьМемориКласс:64

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

  • Samsung Галактика Ядро Плюс
    • МаксПамять:(В комментарии не указано)
    • получитьМемориКласс:48
    • большойМемориКласс:128

Согласно комментарию cmcromance:

  • Galaxy S3 (Jelly Bean) большая куча
    • МаксПамять:268435456
    • получитьМемориКласс:64

И (процентные комментарии):

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

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

  • Huawei Nexus 6P (6.0.1) нормальный
    • МаксПамять:201326592
    • получитьМемориКласс:192

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

Мой ожидание (что, по-видимому, поддерживается приведенными выше числами bigHeap) будет заключаться в том, что эта опция будет иметь эффект, аналогичный настройке кучи вручную через корневую ОС, т. е. она повысит значение maxMemory() уходя getMemoryClass() один.Существует еще один метод getLargeMemoryClass(), который указывает, сколько памяти разрешено приложению с использованием параметра bigHeap.В документации к 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() указывает на то, что разрешено.

Другие советы

Официальный API. является:

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

Debug.getNativeHeapSize() сделаю трюк, я должен подумать. Это было там с 1,0, хотя.

То 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 (я не проверил его в другом месте), он возвращает неправильное значение, если пользователь устанавливает размер кучи вручную.

Некоторые операции быстрее, чем 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();
  }
}

Asus Nexus 7 (2013) 32GIG: GetMemoryClass () = 192 MaxMemory () = 201326592

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

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

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

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

Значение B.

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

Значение МБ

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top