У меня есть несколько вопросов относительно объектов и памяти Bitmap и их общей таксономии.
- Что такое встроенное растровое изображение в памяти?
- Как память Bitmap отличается от памяти кучи?
У меня есть несколько вопросов относительно объектов и памяти Bitmap и их общей таксономии.
Память, которая поддерживает объект Bitmap, выделяется с использованием собственного кода (malloc()
), а не ключевого слова Java new
. Это означает, что память управляется непосредственно ОС, а не Dalvik.
Единственное реальное различие между нативной кучей и кучей Dalvik заключается в том, что куча Dalvik - это сбор мусора, а родной - нет.
Для этих целей, однако, здесь нет большой разницы. Когда ваш объект Bitmap получает сбор мусора, он деструктор будет перерабатывать связанную память в нативной куче.
Источник:
Здесь есть важная тонкость: хотя пиксели Bitmap выделяются в нативной куче, некоторые специальные трюки в Dalvik заставляют ее учитываться в куче Java. Это делается по двум причинам:
(1) Для управления объемом памяти приложение распределяет это. Без учета приложение может выделять огромное количество памяти (так как сам объект Bitmap очень мал, но может удерживаться на произвольно большой объем встроенной памяти), выходящий за пределы допустимого кучи 16 МБ или 24 МБ.
(2) Чтобы определить, когда GC. Без учета вы могли бы выделять и выпускать ссылки на 100 объектов Bitmap; GC не будет работать, потому что эти объекты являются крошечными, но на самом деле они могут представлять собой большое количество мегабайт фактических распределений, которые теперь не GCed своевременно. Учет этих распределений против кучи Java, сборщик мусора будет работать, поскольку он считает, что используется память.
Обратите внимание, что во многих отношениях это деталь реализации; очень вероятно, что он может измениться в будущем, хотя это основное поведение останется в той или иной форме, поскольку они являются важными характеристиками для управления распределением растровых изображений.
Из развертываний в дикой природе я обнаружил следующие устройства:
24 MiB, как правило, является устройством с высоким разрешением и может быть обнаружен с помощью Runtime.getRuntime(). maxMemory(). Там также 32MiB устройства, и некоторые из корневых телефонов имеют 64MiB по умолчанию. Раньше я несколько раз путал себя, пытаясь понять, что происходит. Я думаю, что все устройства подсчитывают растровые изображения в пределе кучи. Но очень сложно сделать какие-либо широкие обобщения о флоте андроидов.
Это ОЧЕНЬ неприятная проблема на Android и очень запутанная. Этот предел и его поведение плохо документированы, сложны и крайне неинтуитивны. Они также различаются в разных устройствах и версиях ОС и имеют несколько известных ошибок. Частью проблемы является то, что пределы не точны - из-за фрагментации кучи, вы попадете в OOM задолго до фактического предела и должны консервативно оставить мега или два буфера. Хуже того, у меня есть несколько устройств, где есть собственный segfault (100% ошибка в самом Android), которая возникает до того, как вы получите исключение Java OOM, что делает его вдвойне важным никогда не достигать предела, поскольку вы даже не можете поймать родной аварии. Более подробную информацию о моих исследованиях можно найти в этом сообщении. В том же сообщении я объясняю, как измерить использование против лимита и избежать сбоев.
Размер кучи java - это Runtime.getRuntime(). totalMemory().
Нет простого способа измерения размера собственного растрового хранилища. Общая нативная куча может быть измерена с помощью Debug.getNativeHeapAllocatedSize(), но только растровые изображения подсчитываются до предела (я думаю).
Мы можем увеличить размер кучи, используя android:largeheap="true"
в вашем файле манифеста. Это решит вашу проблему.