Android: как работает Bitmap recycle ()? - PullRequest
79 голосов
/ 29 сентября 2010

Допустим, я загрузил изображение в объект растрового изображения, например

Bitmap myBitmap = BitmapFactory.decodeFile(myFile);

. Что произойдет, если я загружу другое растровое изображение, например

myBitmap = BitmapFactory.decodeFile(myFile2);

Что произойдет с первым myBitmap??Получает ли он сбор мусора или мне приходится вручную собирать мусор перед загрузкой другого растрового изображения, например.myBitmap.recycle()?

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

Ответы [ 5 ]

69 голосов
/ 30 сентября 2010

Первое растровое изображение не является собранным мусором при декодировании второго. Сборщик мусора сделает это позже, когда решит. Если вы хотите освободить память как можно скорее, вы должны вызвать recycle() непосредственно перед декодированием второго растрового изображения.

Если вы хотите загрузить действительно большое изображение, вам следует пересмотреть его. Вот пример: Странно нехватка памяти при загрузке изображения в растровый объект .

21 голосов
/ 29 ноября 2012

Я думаю, что проблема заключается в следующем: в версиях Android, предшествующих Honeycomb, фактические необработанные растровые данные хранятся не в памяти виртуальной машины, а в собственной памяти. Эта собственная память освобождается , когда соответствующий объект java Bitmap имеет значение GC'd.

Однако , когда у вас заканчивается собственная память, dalvik GC не запускается, поэтому возможно, что ваше приложение использует очень мало памяти java, поэтому dalvik GC никогда не вызывается, тем не менее он использует тонны собственной памяти для растровых изображений, что в конечном итоге вызывает ошибку OOM.

По крайней мере, это мое предположение. К счастью, в Honeycomb и более поздних версиях все растровые данные хранятся на виртуальной машине, поэтому вам вообще не нужно использовать recycle(). Но для миллионов пользователей 2.3 (фрагментация сотрясает кулак ), вы должны использовать recycle() везде, где это возможно (огромные хлопоты). Или же вы можете вместо этого вызвать GC.

21 голосов
/ 11 июля 2011

Вам необходимо вызвать myBitmap.recycle () перед загрузкой следующего изображения.

В зависимости от источника вашего myFile (например, если это что-то, что вы не можете контролировать по размеру оригинала), при загрузке изображения вместо простого пересчета произвольного числа, вы должны масштабировать изображение до размера дисплея.

if (myBitmap != null) {
    myBitmap.recycle();
    myBitmap = null;
}
Bitmap original = BitmapFactory.decodeFile(myFile);
myBitmap = Bitmap.createScaledBitmap(original, displayWidth, displayHeight, true);
if (original != myBitmap)
    original.recycle();
original = null;

Я кэширую displayWidth & displayHeight в статическом состоянии, которое я инициализировал в начале своей Деятельности.

Display display = getWindowManager().getDefaultDisplay();
displayWidth = display.getWidth();
displayHeight = display.getHeight();
10 голосов
/ 22 мая 2012

После того как растровое изображение было загружено в память, фактически оно было создано из двух частей данных.Первая часть включает в себя некоторую информацию о растровом изображении, другая часть включает в себя информацию о пикселях растрового изображения (оно размечается байтовым массивом)Первая часть существует в используемой памяти Java, вторая часть существует в используемой памяти C ++.Он может использовать память друг друга напрямую.Bitmap.recycle () используется для освобождения памяти C ++.Если вы только это сделаете, GC соберет часть java, и память C всегда будет использоваться.

8 голосов
/ 09 апреля 2013

Timmmm был прав.

в соответствии с: http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html

Кроме того, до Android 3.0 (API Level 11) данные поддержки растрового изображения сохранялись ввстроенная память, которая не высвобождается предсказуемым образом, что может привести к кратковременному превышению приложением пределов памяти и падению.

...