Android: Bitmap recycle() как это работает?

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

Bitmap myBitmap = BitmapFactory.decodeFile(myFile);

Теперь, что произойдет, если я загружу другое растровое изображение вроде

myBitmap = BitmapFactory.decodeFile(myFile2);

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

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

Ответ 1

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

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

Ответ 2

Перед загрузкой следующего изображения вам нужно будет вызвать 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();

Ответ 3

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

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

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

Ответ 4

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

Ответ 5

Тимммм был прав.

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

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