Bitmap OutOfMemoryError даже с использованием recycle()

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

Когда вы касаетесь экрана, создается новое действие, а в предыдущем действии вызывается завершение и переработка растрового изображения:

public void clean() {
    if(this.myBitmap != null){
        Log.d(DEBUG_TAG, " Cleaning  "+this);
        this.myBitmap.recycle();
        this.myBitmap=null;
        System.gc();
    }
}

проблема в том, что требуемая память растет и растет, и когда я запускаю более 12-13 действий, эти сообщения отображаются в logcat:

05-05 16:03:02.909: I/dalvikvm-heap(24794): Clamp target GC heap from 65.790MB to 64.000MB
05-05 16:03:02.969: D/dalvikvm(24794): GC_EXPLICIT freed 71K, 5% free 59008K/61680K, paused 2ms+13ms, total 55ms
05-05 16:03:03.559: I/dalvikvm-heap(24794): Clamp target GC heap from 67.197MB to 64.000MB
05-05 16:03:03.569: D/dalvikvm(24794): GC_EXPLICIT freed 418K, 2% free 60521K/61680K, paused 3ms+28ms, total 109ms

после нескольких действий я получил этот сбой:

05-05 16:03:05.049: E/AndroidRuntime(24794): java.lang.OutOfMemoryError
05-05 16:03:05.049: E/AndroidRuntime(24794):    at android.graphics.Bitmap.nativeCreate(Native Method)
05-05 16:03:05.049: E/AndroidRuntime(24794):    at android.graphics.Bitmap.createBitmap(Bitmap.java:809)
05-05 16:03:05.049: E/AndroidRuntime(24794):    at android.graphics.Bitmap.createBitmap(Bitmap.java:786)
05-05 16:03:05.049: E/AndroidRuntime(24794):    at android.graphics.Bitmap.createBitmap(Bitmap.java:718)

Я не знаю, что здесь происходит, я делаю recycle() растрового изображения, а также пробовал с System.gc() и без него, в обоих случаях я получил сбой


person NullPointerException    schedule 05.05.2014    source источник
comment
Добавляете ли вы флаг largeHeapSize в свое приложение?   -  person Sergey Shustikov    schedule 05.05.2014
comment
мммм, спасибо, deathember, кажется, это улучшило мое приложение, но я думаю, что это не окончательное решение.   -  person NullPointerException    schedule 05.05.2014
comment
Позвольте мне объяснить вам. Когда вы используете большие растровые изображения в своей памяти, вы даете OME. Больше растровых изображений — больше шансов получить OUME. Добавление флага неплохой способ, потому что Android дает вам максимальный размер кучи для загрузки ваших объектов в память. Google это для управления памятью для Android Романа Гая. Google рекомендовал вам использовать этот флаг. Но у вас есть другой способ. Посмотрите на свой код и, возможно, вы сможете его улучшить и, возможно, это исправит ваш OME.   -  person Sergey Shustikov    schedule 05.05.2014


Ответы (2)


Это известная ошибка, это не из-за больших файлов. Поскольку Android кэширует Drawables, его память уходит после использования нескольких изображений. Но я нашел для этого альтернативный способ, пропустив систему кеша Android по умолчанию.

Решение: создайте папку с возможностью рисования в ресурсах и переместите изображения в папку с возможностью рисования в ресурсах и используйте следующую функцию, чтобы получить BitmapDrawable.

public static Drawable getAssetImage(Context context, String filename) throws IOException {
    AssetManager assets = context.getResources().getAssets();
    InputStream buffer = new BufferedInputStream((assets.open("drawable/" + filename + ".png")));
    Bitmap bitmap = BitmapFactory.decodeStream(buffer);
    return new BitmapDrawable(context.getResources(), bitmap);
}

Ссылка: https://stackoverflow.com/posts/6116316/revisions

Кроме того, добавьте строку ниже в файл манифеста.

android:largeHeap="true"
person Quamber Ali    schedule 05.05.2014

Используйте DDMS, чтобы получить дамп кучи и выполнить некоторый анализ дампа с помощью Eclipse Memory Analyzer (встроенного в Eclipse ADT или работающего автономно). То, что вы ищете, это объекты, которые вы выделили, но не освобождаете. Одна из возможностей заключается в том, что вы пропускаете действия. Вы говорите, что ошибка OOM возникает после запуска 12-13 действий. Одновременно должно быть видно только одно из действий, чтобы вы могли освободить память от приостановленных действий в методе onPause() или onStop(). Опять же, анализ дампа кучи даст вам хорошее представление о том, что занимает память кучи.

К сведению: Bitmap#recycle() действительно необходим только на устройствах Gingerbread и более ранних версиях. В более новой версии ОС растровые изображения хранятся в куче и удаляются сборщиком мусора, как и другие объекты. См. раздел «Управление памятью на Android 2.3.3 и ниже» этого документа: https://developer.android.com/training/displaying-bitmaps/manage-memory.html

person Matt Accola    schedule 05.05.2014