Как вы программно определяете размер кучи приложения, доступного для приложения Android?
Я слышал, что есть функция, которая делает это в более поздних версиях SDK. В любом случае, я ищу решение, которое работает на 1,5 и выше.
Как вы программно определяете размер кучи приложения, доступного для приложения Android?
Я слышал, что есть функция, которая делает это в более поздних версиях SDK. В любом случае, я ищу решение, которое работает на 1,5 и выше.
Ответы:
Есть два способа подумать о вашей фразе «доступный размер кучи приложения»:
Сколько кучи может использовать мое приложение до появления серьезной ошибки? И
Сколько кучи должно использовать мое приложение, учитывая ограничения версии ОС 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, с использованием двух разных (устанавливаемых вручную) значений кучи для каждого:
В дополнение к вышесказанному, я протестировал планшет Novo7 Paladin с Ice Cream Sandwich. По сути, это была стандартная версия ICS, за исключением того, что я проверил планшет через простой процесс, который не заменяет всю ОС, и, в частности, не предоставляет интерфейс, который позволял бы настраивать размер кучи вручную.
Для этого устройства вот результаты:
Также (за Кишора в комментарии ниже):
И (согласно комментарию Акауппи):
За комментарий от cmcromance:
И (комментарии tencent):
Другие устройства
Я не тестировал эти два метода, используя специальный параметр android: largeHeap = "true", доступный со времен Honeycomb, но благодаря cmcromance и tencent у нас есть некоторые примерные значения largeHeap, как сообщалось выше.
Мои ожидания (которые , как представляется, поддерживаются числами 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, вероятно , возвращает значение 16MB, но я делать видим , что в моих (много позже) CyanogenMod версий пользователей Можно выбрать значение кучи до 12 МБ, что, вероятно, приведет к более низкому пределу кучи, и поэтому я бы посоветовал вам продолжить тестировать это maxMemory()
значение даже для версий ОС до 2.0. Возможно, вам даже придется отказаться от запуска в маловероятном случае, если это значение установлено даже ниже 16 МБ, если вам нужно иметь больше, чем maxMemory()
указано, разрешено.
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 (я не проверял его в других местах) он возвращает неправильное значение, если пользователь устанавливает размер кучи вручную.
getMemoryClass
видимому, подразумевает, что число может не совпадать с доступным размером кучи для вашего виртуального компьютера, а поскольку документ для getNativeHeapSize
... молчалив, я действительно думаю, что Runtime.getRuntime().maxMemory()
это лучший ответ.
Некоторые операции выполняются быстрее, чем менеджер пространства кучи 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();
}
}
AvailableMemoryPercentage
в соответствии с формулой: сколько памяти устройства в настоящее время свободно. MIN_AVAILABLE_MEMORY_PERCENTAGE
ваш пользовательский параметр, порог, при котором вы начинаете ждать, пока сборщик мусора выполнит свою работу.
Asus Nexus 7 (2013) 32Gig: getMemoryClass () = 192 maxMemory () = 201326592
Я сделал ошибку, прототипировав свою игру на Nexus 7, а затем обнаружил, что почти сразу же не хватило памяти на обычном планшете моей жены 4.04 (memoryclass 48, maxmemory 50331648)
Мне нужно будет реструктурировать свой проект, чтобы загружать меньше ресурсов, когда я определяю, что класс памяти мал.
Есть ли способ в Java, чтобы увидеть текущий размер кучи? (Я вижу это ясно в logCat при отладке, но мне бы хотелось, чтобы это можно было увидеть в коде для адаптации, например, если currentheap> (maxmemory / 2) выгружает высококачественные растровые изображения загружает низкое качество
Вы имеете в виду программно или просто во время разработки и отладки? Если последнее, вы можете увидеть эту информацию с точки зрения DDMS в Eclipse. Когда ваш эмулятор (возможно, даже физический телефон, который подключен) работает, он выведет список активных процессов в окне слева. Вы можете выбрать его, и есть возможность отслеживать распределение кучи.
Runtime rt = Runtime.getRuntime();
rt.maxMemory()
значение b
ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
am.getMemoryClass()
значение МБ
rt
? Где это заявлено?