Как решить проблему java.lang.OutOfMemoryError в Android

Хотя у меня очень маленькое изображение в папке с возможностью рисования, я получаю эту ошибку от пользователей. И я не использую функцию bitmap в коде. По крайней мере намеренно 🙂

java.lang.OutOfMemoryError at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method) at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:683) at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:513) at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:889) at android.content.res.Resources.loadDrawable(Resources.java:3436) at android.content.res.Resources.getDrawable(Resources.java:1909) at android.view.View.setBackgroundResource(View.java:16251) at com.autkusoytas.bilbakalim.SoruEkrani.cevapSecimi(SoruEkrani.java:666) at com.autkusoytas.bilbakalim.SoruEkrani$9$1.run(SoruEkrani.java:862) at android.os.Handler.handleCallback(Handler.java:733) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:146) at android.app.ActivityThread.main(ActivityThread.java:5602) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:515) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1283) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1099) at dalvik.system.NativeStart.main(Native Method) 

В соответствии с этим stackTrace я получаю эту ошибку на этой строке («tv» – это textView):

 tv.setBackgroundResource(R.drawable.yanlis); 

В чем проблема? Если вам нужна другая информация о коде, я могу добавить ее. Благодаря!

Solutions Collecting From Web of "Как решить проблему java.lang.OutOfMemoryError в Android"

Вы не можете увеличить размер кучи динамически, но вы можете попросить использовать больше с помощью.

андроид: largeHeap = "истина"

В manifest.xml вы можете добавить в свой манифест эти строки, которые он работает для некоторых ситуаций.

 <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:largeHeap="true" android:supportsRtl="true" android:theme="@style/AppTheme"> 

Должны ли быть созданы процессы вашего приложения с большой кучей Dalvik. Это относится ко всем процессам, созданным для приложения. Он применяется только к первому приложению, загружаемому в процесс; Если вы используете общий идентификатор пользователя, чтобы позволить нескольким приложениям использовать процесс, все они должны использовать этот параметр последовательно или у них будут непредсказуемые результаты. Большинство приложений не должны этого нуждаться и вместо этого должны сосредоточиться на сокращении общего использования памяти для повышения производительности. Включение этого также не гарантирует фиксированного увеличения доступной памяти, поскольку некоторые устройства ограничены их общей доступной памятью.


Чтобы запросить доступный размер памяти во время выполнения, используйте методы getMemoryClass() или getLargeMemoryClass() .

Если все еще стоит проблема, тогда это также должно работать

  BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = 8; mBitmapInsurance = BitmapFactory.decodeFile(mCurrentPhotoPath,options); 

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

Это оптимальное использование BitmapFactory.Options.inSampleSize относительно скорости отображения изображения. В документации упоминаются значения, которые имеют мощность 2, поэтому я работаю с 2, 4, 8, 16 и т. Д.

Давайте углубимся в Image Sampling:

Например, не стоит загружать изображение с разрешением 1024×768 пикселей в память, если в конечном итоге оно будет отображаться в миниатюре размером 128×128 пикселей в ImageView .

Чтобы inSampleSize декодер для подвыражения изображения, загрузив меньшую версию в память, установите для inSampleSize значение true в свой объект BitmapFactory.Options . Например, изображение с разрешением 2100 x 1500 пикселей, которое декодируется с помощью параметра inSampleSize 4, создает растровое изображение приблизительно 512×384. Загрузка этого в память использует 0,75 МБ, а не 12 МБ для полного изображения (при условии конфигурации растрового изображения ARGB_8888 ). Ниже приведен метод вычисления значения размера выборки, который представляет собой мощность двух на основе ширины и высоты цели:

 public static int calculateInSampleSize( BitmapFactory.Options options, int reqWidth, int reqHeight) { // Raw height and width of image final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { final int halfHeight = height / 2; final int halfWidth = width / 2; // Calculate the largest inSampleSize value that is a power of 2 and keeps both // height and width larger than the requested height and width. while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) { inSampleSize *= 2; } } return inSampleSize; } 

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

Чтобы использовать этот метод, сначала inJustDecodeBounds декодирование с параметром inJustDecodeBounds установленным в true , передайте параметры и затем снова декодируйте, используя новое значение inJustDecodeBounds а inJustDecodeBoundsfalse :

 public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) { // First decode with inJustDecodeBounds=true to check dimensions final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeResource(res, resId, options); // Calculate inSampleSize options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); // Decode bitmap with inSampleSize set options.inJustDecodeBounds = false; return BitmapFactory.decodeResource(res, resId, options); } 

Этот метод упрощает загрузку растрового изображения произвольно большого размера в ImageView который отображает миниатюру размером 100×100 пикселей, как показано в следующем примере кода:

 mImageView.setImageBitmap(decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100)); 

Вы можете выполнить аналогичный процесс для декодирования растровых изображений из других источников, заменив соответствующий метод BitmapFactory.decode* мере необходимости.


Я нашел этот код интересным:

 private Bitmap getBitmap(String path) { Uri uri = getImageUri(path); InputStream in = null; try { final int IMAGE_MAX_SIZE = 1200000; // 1.2MP in = mContentResolver.openInputStream(uri); // Decode image size BitmapFactory.Options o = new BitmapFactory.Options(); o.inJustDecodeBounds = true; BitmapFactory.decodeStream(in, null, o); in.close(); int scale = 1; while ((o.outWidth * o.outHeight) * (1 / Math.pow(scale, 2)) > IMAGE_MAX_SIZE) { scale++; } Log.d(TAG, "scale = " + scale + ", orig-width: " + o.outWidth + ", orig-height: " + o.outHeight); Bitmap bitmap = null; in = mContentResolver.openInputStream(uri); if (scale > 1) { scale--; // scale to max possible inSampleSize that still yields an image // larger than target o = new BitmapFactory.Options(); o.inSampleSize = scale; bitmap = BitmapFactory.decodeStream(in, null, o); // resize to desired dimensions int height = bitmap.getHeight(); int width = bitmap.getWidth(); Log.d(TAG, "1th scale operation dimenions - width: " + width + ", height: " + height); double y = Math.sqrt(IMAGE_MAX_SIZE / (((double) width) / height)); double x = (y / height) * width; Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, (int) x, (int) y, true); bitmap.recycle(); bitmap = scaledBitmap; System.gc(); } else { bitmap = BitmapFactory.decodeStream(in); } in.close(); Log.d(TAG, "bitmap size - width: " +bitmap.getWidth() + ", height: " + bitmap.getHeight()); return bitmap; } catch (IOException e) { Log.e(TAG, e.getMessage(),e); return null; } 

Как управлять памятью вашего приложения: ссылка


Не рекомендуется использовать android:largeHeap="true" Вот выдержка из Google, которая объясняет это,

Однако возможность запросить большую кучу предназначена только для небольшого набора приложений, которые могут оправдать необходимость потреблять больше ОЗУ (например, большое приложение для редактирования фотографий). Никогда не запрашивайте большую кучу просто потому, что у вас закончилась нехватка памяти, и вам нужно быстрое исправление – вы должны использовать ее только тогда, когда вы точно знаете, где находится вся ваша память, и почему ее необходимо сохранить. Тем не менее, даже если вы уверены, что ваше приложение может оправдать большую кучу, вы должны избегать его запроса в любой возможной степени. Использование дополнительной памяти будет в большей степени нарушать общий пользовательский интерфейс, поскольку сбор мусора займет больше времени, а производительность системы может быть медленнее при переключении задач или выполнении других общих операций.

После работы excrutiatingly с out of memory errors я бы сказал, добавив это в манифест, чтобы избежать проблемы с oom, не является грехом


Проверка поведения приложения на Android Runtime (ART)

Время выполнения Android (ART) является средой исполнения по умолчанию для устройств под управлением Android 5.0 (API уровня 21) и выше. Эта среда исполнения предлагает ряд функций, которые повышают производительность и плавность платформы Android и приложений. Вы можете найти более подробную информацию о новых возможностях ART в представлении ART .

Однако некоторые методы, которые работают на Дальвике, не работают на АРТ. Этот документ позволяет вам узнать о том, что нужно посмотреть при переносе существующего приложения для совместимости с АРТ. Большинство приложений должны работать только при работе с АРТ.


Решение проблем сбора мусора (GC)

В Dalvik приложениям часто бывает полезно явно вызвать System.gc (), чтобы вызвать сборку мусора (GC). Это должно быть гораздо менее необходимо для АРТ, особенно если вы вызываете сборку мусора, чтобы предотвратить появление типа GC_FOR_ALLOC или уменьшить фрагментацию. Вы можете проверить, какая среда исполнения используется, вызывая System.getProperty («java.vm.version»). Если АРТ используется, значение свойства «2.0.0» или выше.

Кроме того, в Android Open Source Project (AOSP) разрабатывается компактный сборщик мусора для улучшения управления памятью. Из-за этого вам следует избегать использования методов, несовместимых с уплотнением GC (например, сохранение указателей на данные экземпляра объекта). Это особенно важно для приложений, которые используют интерфейс Java Native Interface (JNI). Дополнительные сведения см. В разделе Предупреждение проблем JNI.


Предотвращение проблем JNI

JNI от ART несколько более строг, чем у Dalvik's. Особенно полезно использовать режим CheckJNI для обнаружения общих проблем. Если ваше приложение использует код C / C ++, вы должны просмотреть следующую статью:


Кроме того, вы можете использовать встроенную память ( NDK & JNI ), поэтому вы фактически обходите ограничение размера кучи.

Вот несколько сообщений об этом:

  • Как кэшировать растровые изображения в родной памяти

  • https://stackoverflow.com/a/9428660/1761003

  • JNI, чтобы помочь избежать OOM при использовании больших изображений

И вот библиотека, созданная для него:

Вы должны реализовать диспетчер кэша LRU при работе с растровым изображением

http://developer.android.com/reference/android/util/LruCache.html http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html Когда следует перерабатывать растровое изображение с использованием LRUCache?

ИЛИ

Используйте библиотеку уровня, например Universal Image Loader:

https://github.com/nostra13/Android-Universal-Image-Loader

РЕДАКТИРОВАТЬ :

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

https://github.com/bumptech/glide

Я вижу только два варианта:

  1. У вас есть утечки памяти в приложении.
  2. У устройств недостаточно памяти при запуске приложения.