Jak rozwiązać Javę.lang.OutOfMemoryError problem w Androidzie

Alough mam bardzo mały rozmiar obrazu w folderze drawable, dostaję ten błąd od użytkowników. I nie używam żadnej funkcji bitmapowej w kodzie. Przynajmniej celowo :)

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)

Zgodnie z tym stackTrace dostaję ten błąd w tej linii ('tv' to textView):

tv.setBackgroundResource(R.drawable.yanlis);
W czym problem? Jeśli potrzebujesz innych informacji o kodzie, mogę go dodać. Dzięki!
Author: Utku Soytaş, 2014-09-08

4 answers

Nie możesz dynamicznie zwiększać rozmiaru sterty, ale możesz poprosić o użycie większej ilości za pomocą.

Android: largeHeap= "true"

W manifest.xml możesz dodać do manifestu te linie, które działają w niektórych sytuacjach.

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

Czy procesy aplikacji powinny być tworzone za pomocą dużej sterty Dalvik. Dotyczy to wszystkich procesów utworzonych dla aplikacji. Dotyczy tylko pierwszej aplikacji załadowanej do procesu; jeśli korzystając ze współdzielonego identyfikatora użytkownika, aby umożliwić wielu aplikacjom korzystanie z procesu, wszystkie muszą konsekwentnie korzystać z tej opcji, w przeciwnym razie będą miały nieprzewidywalne wyniki. Większość aplikacji nie powinna tego potrzebować, a zamiast tego powinna skupić się na zmniejszeniu ogólnego zużycia pamięci w celu poprawy wydajności. Włączenie tej opcji nie gwarantuje stałego wzrostu dostępnej pamięci, ponieważ niektóre urządzenia są ograniczone przez ich całkowitą dostępną pamięć.


Aby sprawdzić Dostępny rozmiar pamięci w czasie wykonywania, użyj metod getMemoryClass() lub getLargeMemoryClass().

Jeśli nadal napotykasz problem, to powinno to również zadziałać

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

Jeśli jest ustawiona na wartość > 1, żąda, aby dekoder podsamplował oryginalny obraz, zwracając mniejszy obraz, aby zapisać pamięć.

Jest to optymalne wykorzystanie BitmapFactory.Opcje.inSampleSize w odniesieniu do szybkości wyświetlania obrazu. Dokumentacja wspomina o używaniu wartości, które są mocą 2, więc pracuję z 2, 4, 8, 16 itd.

Lets get more głębiej do próbkowania obrazu:

Na przykład, nie warto ładować do pamięci obrazu o rozdzielczości 1024x768 pikseli, jeśli zostanie on wyświetlony w miniaturze 128x128 pikseli w ImageView.

Aby powiedzieć dekoderowi, aby podsamplował obraz, ładując mniejszą wersję do pamięci, Ustaw inSampleSize na true w obiekcie BitmapFactory.Options. Na przykład obraz o rozdzielczości 2100 x 1500 pikseli, który jest dekodowany inSampleSize 4, tworzy bitmapę o rozdzielczości około 512x384. Wczytywanie tego do pamięci wykorzystuje 0,75 MB zamiast 12 MB dla pełnego obrazu(zakładając konfigurację bitmapy ARGB_8888). Oto metoda obliczania wartości wielkości próbki, która jest potęgą dwóch na podstawie docelowej szerokości i wysokości:

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;
}

Uwaga : moc dwóch wartości jest obliczana, ponieważ dekoder używa wartość końcowa przez zaokrąglenie w dół do najbliższej potęgi dwóch, zgodnie z inSampleSize Dokumentacja.

Aby użyć tej metody, najpierw odkoduj z inJustDecodeBounds ustawioną na true, przekaż opcje następnie dekoduj ponownie używając nowej wartości inSampleSize i inJustDecodeBounds ustawionej na false:

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);
}

Ta metoda ułatwia załadowanie bitmapy o arbitralnie dużych rozmiarach do ImageView, która wyświetla miniaturę 100x100 pikseli, jak pokazano w poniższym przykładowym kodzie:

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

Możesz wykonać podobny proces dekodowania bitmap z innych źródeł, zastępując odpowiednią metodę BitmapFactory.decode* w razie potrzeby.


Znalazłem również ten kod ciekawe:

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;
}

Jak zarządzać pamięcią aplikacji: link

to nie jest dobry pomysł, aby używać android:largeHeap="true" Oto wyciąg z google, który to wyjaśnia,

Jednak możliwość żądania dużej sterty jest przeznaczona tylko dla mały zestaw aplikacji, które mogą uzasadniać konieczność zużywania większej ilości pamięci RAM (np. jako duża aplikacja do edycji zdjęć). Nigdy nie żądaj dużej sterty po prostu ponieważ zabrakło Ci pamięci i potrzebujesz szybkiego fix - powinieneś używaj go tylko wtedy, gdy wiesz dokładnie, gdzie jest cała twoja pamięć przydzielone i dlaczego należy je zachować. A jednak, nawet gdy jesteś pewny siebie Twoja aplikacja może uzasadnić dużą stertę, należy unikać żądania go do w miarę możliwości. Korzystanie z dodatkowej pamięci będzie coraz częściej ze szkodą dla ogólnego doświadczenia użytkownika, ponieważ śmieci gromadzenie danych będzie trwało dłużej, a wydajność systemu może być wolniejsza, gdy przełączanie zadań lub wykonywanie innych wspólnych szef.

Po przepracowaniu z out of memory errors powiedziałbym, że dodanie tego do manifestu, aby uniknąć problemu oom, nie jest grzechem


[[48]}weryfikacja zachowania aplikacji w środowisku uruchomieniowym Androida (ART) [25]} Android runtime (ART) jest domyślnym środowiskiem uruchomieniowym dla urządzeń z systemem Android 5.0 (poziom API 21) i wyższym. To środowisko uruchomieniowe oferuje wiele funkcji, które poprawiają wydajność i płynność platformy i aplikacji Android. Więcej informacji na temat ART ' s nowe funkcje w przedstawiające sztukę .

jednak niektóre techniki, które działają na Dalvik nie działają na sztuce. Ten dokument informuje o rzeczach, na które należy zwrócić uwagę podczas migracji istniejącej aplikacji, aby była zgodna z art. Większość aplikacji powinna działać tylko podczas pracy z art.


Rozwiązywanie problemów związanych ze zbieraniem śmieci (Gc)

Pod Dalvik, aplikacje często znaleźć przydatne do jawnego wywołania systemu.gc () to prompt garbage collection (GC). Powinno to być znacznie mniej konieczne w przypadku ART, szczególnie jeśli wywołasz garbage collection, aby zapobiec wystąpieniu typu GC_FOR_ALLOC lub zmniejszyć fragmentację. Możesz sprawdzić, które środowisko uruchomieniowe jest używane przez wywołanie System.getProperty ("java.vm.wersja"). Jeśli ART jest w użyciu, wartość właściwości jest "2.0.0" lub wyższa.

Ponadto w Android Open-Source Project (AOSP) rozwijany jest kompaktowy garbage collector, który ma na celu usprawnienie zarządzania pamięcią. Z tego powodu należy unikać używania techniki, które są niezgodne z zagęszczaniem GC (takie jak zapisywanie wskaźników do danych instancji obiektu). Jest to szczególnie ważne w przypadku aplikacji wykorzystujących natywny interfejs Java (JNI). Aby uzyskać więcej informacji, zobacz zapobieganie problemom z JNI.


Zapobieganie problemom JNI

JNI Arta jest nieco bardziej rygorystyczny niż Dalvika. szczególnie dobrym pomysłem jest użycie trybu CheckJNI, aby złapać typowe problemy. Jeśli Twoja aplikacja korzysta z kodu C / C++, powinieneś przejrzeć następujące Artykuł:


Można również użyć pamięci natywnej ( NDK & JNI ), więc faktycznie omija się ograniczenie rozmiaru sterty.

Oto kilka postów na ten temat:

A oto biblioteka stworzona do tego:

 112
Author: Maveňツ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-17 12:22:48

Powinieneś zaimplementować Menedżera pamięci podręcznej LRU, gdy masz do czynienia z bitmapą

Http://developer.android.com/reference/android/util/LruCache.html http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html Kiedy powinienem przetwarzać bitmapę za pomocą LRUCache?

LUB

Użyj biblioteki warstwy, takiej jak Universal Image Loader:

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

EDIT:

Teraz kiedy mając do czynienia z obrazami i przez większość czasu z bitmapą używam Glide, który pozwala skonfigurować moduł Glide i lrucache

Https://github.com/bumptech/glide

 3
Author: An-droid,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-16 08:06:36

Widzę tylko dwie opcje:

    Masz wycieki pamięci w aplikacji.
  1. urządzenia nie mają wystarczającej ilości pamięci podczas uruchamiania aplikacji.
 2
Author: Cativail,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-08 07:57:38

Kilka wskazówek do obsługi takiego błędu / wyjątku dla aplikacji na Androida:

  1. Activities & Application have methods like:

    • onLowMemory
    • onTrimMemory Obsługuj te metody, aby obserwować zużycie pamięci.
  2. Tag w manifeście może mieć atrybut 'largeHeap' ustawiony na TRUE, który żąda więcej Sterty Dla piaskownicy aplikacji.

  3. Zarządzanie buforowaniem w pamięci i buforowaniem dysku:

    • Obrazy i inne dane mogły być buforowane w pamięci podczas uruchamiania aplikacji (lokalnie w działaniach / fragment i globalnie); powinny być zarządzane lub usuwane.
  4. Wykorzystanie WeakReference, SoftReference tworzenia instancji Java, w szczególności do plików.

  5. Jeśli tak wiele obrazów, użyj odpowiedniej struktury biblioteki/danych, która może zarządzać pamięcią, użyj samlingu załadowanych obrazów, zajmij się buforowaniem dysku.

  6. Handle OutOfMemory exception

  7. Postępuj zgodnie z najlepszymi praktykami kodowania

    • wyciek pamięci (Don ' t hold everything with strong reference)
  8. Minimalizuj stos aktywności np. ilość działań w stos (nie przechowuj wszystkiego na context/activty)

    • kontekst ma sens, te dane / instancje, które nie są wymagane poza zakresem (aktywność i fragmenty), trzymają je w odpowiednim kontekście zamiast globalnego przechowywania odniesienia.
  9. Zminimalizuj użycie statyki, o wiele więcej singletonów.

  10. Zadbaj o podstawową pamięć systemu operacyjnego fundamenty

    • problemy z fragmentacją pamięci
  11. Involk GC.Collect () ręcznie czasami, gdy masz pewność, że buforowanie w pamięci nie jest już potrzebne.

 0
Author: Sandipkumar Savani,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-18 12:26:56