Есть два варианта выражения «доступный размер кучи приложения»:
Сколько кучи может использовать мое приложение до появления серьезной ошибки? И
Сколько кучи должно использовать мое приложение, учитывая ограничения версии 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()
, разрешено.