Android - исключение из памяти при создании растрового изображения

Я получаю следующую ошибку после создания растрового изображения во второй раз:

04-17 18:28:09.310: ERROR/AndroidRuntime(3458): java.lang.OutOfMemoryError: bitmap size exceeds VM budget

this._profileBitmap = Bitmap.createBitmap(_profileBitmap, xCoor,  yCoor, width, height);

Из журнала:

04-17 18:27:57.500: INFO/CameraCropView(3458): Original Photo Size: W 1536 x H 2048   
04-17 18:28:06.170: INFO/CameraCropView(3458): xCoor: 291   
04-17 18:28:06.170: INFO/CameraCropView(3458): yCoor: 430    
04-17 18:28:06.170: INFO/CameraCropView(3458): Width: 952  
04-17 18:28:06.170: INFO/CameraCropView(3458): Height: 952  

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

Ответ 1

У меня была такая же проблема, и я решил ее следующим образом:

Мое приложение было размером ~ 18 МБ, и когда я увидел, сколько памяти осталось свободным, я был шокирован - 654 КБ (на 1 ГБ ОЗУ!). Поэтому я просто удалил почти все изображения из проекта и загрузил их из интернета при первом запуске, и при необходимости использовал картинки с SD-карты.

Чтобы проверить общую/свободную память для вашего приложения, используйте:

 Runtime.getRuntime().totalMemory();
 Runtime.getRuntime().freeMemory();

РЕДАКТИРОВАТЬ: я забыл главное - добавить в свой манифест, между тегом приложения, эту строку:

android:largeHeap="true"

Ответ 2

Есть много проблем с исключениями памяти с растровыми изображениями на Android, многие из которых обсуждаются в stackoverflow. Вероятно, было бы лучше, если бы вы рассмотрели существующие вопросы, чтобы узнать, соответствует ли ваша одна из существующих, а если нет, напишите, что отличает вашу ситуацию.

Некоторые примеры:

Исключение из памяти из-за большого размера растрового изображения

Android: исключение из памяти в галерее

Устранение неполадок с ОС Android при обработке изображений

и т.д.: https://stackoverflow.com/search?q=android+out+of+memory+exception+bitmap

Ответ 3

советы по обработке битовых карт Android

Теперь вот советы, которые вы можете использовать, и можете избежать исключения из памяти в своем приложении для Android.

  • Всегда используйте контекст действия вместо контекста приложения. потому что контекст приложения не может быть собранным мусором. И освободите ресурсы по мере завершения вашей деятельности. (жизненный цикл объекта должен быть то же, что и для активности).

2. Когда активность завершается. Проверьте HEAP DUMP (инструмент анализа памяти в студии Android).

Если в HEAP DUMP есть объекты из готовой активности, происходит утечка памяти. просмотрите свои кода и определить, что вызывает утечку памяти.

  1. Всегда использовать inSampleSize

Теперь что такое inSampleSize? с помощью inSampleSize вы на самом деле говорите декодеру, чтобы он не хватал каждый пиксель в памяти, а не образ суб-образца. Это приведет к меньшему количеству пикселей, которые будут загружены в память, чем исходное изображение. вы можете сказать, что декодер захватывает каждый 4-й пиксель или каждый второй пиксель от исходного изображения. если inSampleSize - 4. декодер вернет изображение, равное 1/16 количества пикселей в исходном изображении.

Итак, сколько памяти вы сохранили? вычислить:)

  1. Прочитайте размеры растровых изображений перед загрузкой в ​​память.

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

    использовать inJustBounds = true

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

 BitmapFactory.Options options = new BitmapFactory.Options();
 options.inJustDecodeBounds = true;
 Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.id.myimage,    options);
 int imageHeight = options.outHeight;
 int imageWidth = options.outWidth;
 String imageType = options.outMimeType;

Более фрагмент кода не даст нам никакого изображения/растрового изображения. он вернет значение null для bitmap Object. но он обязательно вернет ширину и высоту этого изображения. который является R.id.myimage.

Теперь у вас есть ширина и высота изображения. вы можете масштабировать или уменьшать изображение на основе этих факторов:

  • Размер ImageView, который будет использоваться для отображения изображения.
  • Доступный объем памяти. вы можете проверить доступный объем памяти с помощью ActivityManager и getMemoryClass.
  • Размер и плотность экрана устройства.

    1. Используйте соответствующую конфигурацию Bitmap

Конфигурации растровых изображений - это цветовое пространство/глубина цвета изображения. Конфигурация растрового изображения по умолчанию в Android - RGB_8888, которая составляет 4 байта на пиксель.

Если вы используете цветной канал RGB_565, который использует 2 байта на пиксель. половина распределения памяти для одного и того же разрешения:)

  1. Используйте свойство inBitmap для целей утилизации.

  2. Не создавайте статический объект Drawable, поскольку он не может быть собранным мусором.

  3. Запросить большую кучу в файле манифеста.

  4. Используйте несколько процессов, если вы выполняете большую обработку изображений (задача с интенсивной памятью) или используйте NDK (Native Development с использованием c, С++)

Ответ 4

Это происходит потому, что вы напрямую загружаете растровое изображение, которое потребляет много памяти. Вместо этого используйте уменьшенную версию изображения в _profileBitmap. Этот парень объясняет это довольно хорошо. http://androidcocktail.blogspot.in/2012/05/solving-bitmap-size-exceeds-vm-budget.html

Ответ 5

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

Ответ 6

Вы можете использовать векторный Drawable. Он использует XML файл для описания вашего изображения, поэтому он потребляет меньше памяти. Для этого вы должны использовать формат SVG для своих изображений, а затем сгенерировать файл xml с помощью одного из этих двух решений:

  • Решение 1. Используйте студию векторных активов в Android Studio: щелкните правой кнопкой мыши на Drawable file в вашем проекте → new → vector asset
  • Решение 2. Используйте веб-сайт svg2android: https://inloop.github.io/svg2android

Ознакомьтесь с этой ссылкой для получения дополнительной информации:
https://developer.android.com/studio/write/vector-asset-studio.html

Ответ 7

С большими изображениями его можно избежать, взяв образцы в меньшие размеры. Используйте ниже пример -

    File f = new File(selectedImagePath); 

    // First decode with inJustDecodeBounds=true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeStream(new FileInputStream(f), null, options); 
    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, 720, 1280); //My device pixel resolution
    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;    
    Bitmap bmpPic = BitmapFactory.decodeStream(new FileInputStream(f), null, options); 


    Bitmap bmpPic1 = Bitmap.createBitmap(bmpPic, 0, 0, bmpPic.getWidth(), bmpPic.getHeight(), mat, true);   
    img.setImageBitmap(bmpPic1);  //img is your ImageView

Справочно http://developer.android.com/training/displaying-bitmaps/load-bitmap.html

Ответ 8

У меня была эта проблема, потому что я изменял растровое изображение один раз, а затем изменял измененную версию во второй раз, в результате чего три версии одного и того же растрового изображения (оригинал плюс две измененные версии) находились в памяти одновременно.

Я исправил это, изменив код редактирования изображения, чтобы применить обе модификации к одному и тому же растровому изображению в качестве своего рода пакетного процесса, сократив вдвое количество модифицированных версий, которые мое приложение должно было хранить в памяти.

Ответ 9

У меня была такая же проблема, когда телефон был выключен и снова включен. Просто установка растровых изображений на нуль и вызов System.gc(); исправлены все проблемы.