BitmapFactory.decodeResource und unerklärlichen Out of Memory

8

Ich erhalte einen merkwürdigen "Out of Memory" -Fehler beim Dekodieren einer aufzeichnbaren Bildressource 960x926px jpg, die 3555856 Byte zuweist. Das Bild wird nur in drawable-xxhdpi (3x) platziert und ich verwende ein hdpi (1,5x) Gerät. Zwei Fragen:

  • Warum bekomme ich den Fehler, obwohl ich genug freien Speicher im Heapspeicher habe?

  • Zuweisung für ein hdpi Gerät sollte ((960/2) x (926/2)) x 4 = 888960 Bytes (nicht 3555856) sein?

Kann mir jemand das erklären?

HINWEIS: Bei der Frage geht es darum, warum ein OOM für 3,5 MB zugewiesen wird, während 22,5 MB freier Speicher zur Verfügung stehen (siehe Protokoll)

  

03-18 17: 30: 15.050 32750-32750 /? D / dalvikvm: GC_FOR_ALLOC befreit   10809K, 49% frei 23735K / 46087K, pausiert 89ms, insgesamt 89ms

     

03-18 17: 30: 15.050 32750-32750 /? I / dalvikvm-heap: Erzwingen der Sammlung   von SoftReferences für 3555856-Byte-Zuweisung

     

03-18 17: 30: 15.160 32750-32750 /? D / dalvikvm: GC_BEFORE_OOM befreit 29K,    49% frei 23705K / 46087K , 103ms pausiert, insgesamt 103ms

     

03-18 17: 30: 15.160 32750-32750 /? E / dalvikvm-heap: Nicht genügend Arbeitsspeicher auf a   3555856-Byte-Zuweisung .

     

03-18 17: 30: 15.160 32750-32750 /? I / dalvikvm: "Haupt" prio = 5 tid = 1   RUNNABLE

     

03-18 17: 30: 15.160 32750-32750 /? I / dalvikvm: | group="Haupt" sCount = 0   dsCount = 0 obj = 0x418fc6a0 selbst = 0x4010c008

     

03-18 17: 30: 15.160 32750-32750 /? I / dalvikvm: | sysTid = 32750 nice = 1   sched = 0/0 cgrp = apps handle = 1075251280

     

03-18 17: 30: 15.160 32750-32750 /? I / dalvikvm: | schedstat = (0 0 0)   utm = 3807 stm = 859 Kern = 0

     

03-18 17: 30: 15.160 32750-32750 /? I / dalvikvm: um   android.graphics.BitmapFactory.nativeDecodeAsset (Native Methode)

     

03-18 17: 30: 15.160 32750-32750 /? I / dalvikvm: um   android.graphics.BitmapFactory.decodeStream (BitmapFactory.java:636)

     

03-18 17: 30: 15.160 32750-32750 /? I / dalvikvm: um   android.graphics.BitmapFactory.decodeResourceStream (BitmapFactory.java:484)   03-18 17: 30: 15.160 32750-32750 /? I / dalvikvm: um   android.graphics.BitmapFactory.decodeResource (BitmapFactory.java:512)

     

03-18 17: 30: 15.160 32750-32750 /? I / dalvikvm: um   android.graphics.BitmapFactory.decodeResource (BitmapFactory.java:542)

    
GPack 18.03.2016, 17:26
quelle

5 Antworten

2

1) Wenn Sie keine kleinere Version im Ordner hdpi haben, wird die engste Übereinstimmung verwendet. Es wird also die xxhdpi verwenden, wenn keine hdpi oder eine drawbare / version existiert.

2) Es wird nicht automatisch skaliert. Es wird in voller Größe angezeigt.

3) Wenn dies eine OOM verursacht, verwenden Sie wahrscheinlich zu viel Speicher im Allgemeinen.

    
Gabe Sechan 18.03.2016 17:31
quelle
2

Der Grund, warum Sie OOM erhalten, ist, dass wenn das Bild in den Speicher decodiert wird, seine Bitmap mehr Größe als die Bildauflösung hat (fast 4 Mal bin ich nicht sicher über diesen Wert).

Bei der Arbeit mit Bildern sind einige Punkte zu beachten:

  1. Behandle niemals Bitmaps im Hauptthread. Mach die ganze Dekodierung im Hintergrund.
  2. Berücksichtigen Sie immer die Bildschirmgröße oder Größe der Ansicht, in die Sie das Bild einfügen möchten. Zum Beispiel, wenn die Größe Ihres Bildschirms ist 360X720 (einige zufällige Wert), dann ist es keine gute Idee, die volle Auflösung Bild mit einer Auflösung größer als die erforderliche Größe zu dekodieren (wie es vollständige Bitmap im Hauptspeicher laden wird). Also teste immer beim Entschlüsseln.

Versuchen Sie also, die folgende Lösung zu verwenden:

Schritt 1: Suchen Sie die Bildschirmgröße

Entnommen aus hier

%Vor%

Schritt 1: Erstellen Sie eine asynchrone Aufgabe zum Dekodieren von Bitmap

Wenn Sie eine Async-Aufgabe als innere Klasse verwenden, sollten Sie die Verwendung der öffentlichen statischen inneren Klasse in Erwägung ziehen (um Speicherleckprobleme zu vermeiden) und die schwache Referenz der Bildansicht beibehalten, in die das Bild geladen werden soll. Übergeben Sie auch die Bildressource oder -datei oder den Stream, den Sie dekodieren möchten, an den Konstruktor. Im folgenden Code wird davon ausgegangen, dass Sie eine Ressource dekodieren möchten. Übergeben Sie auch die in Schritt 1 berechnete Breite und Höhe.

%Vor%

Referenzen:

Bitmaps

    
Ankit Aggarwal 02.05.2016 21:09
quelle
1

Die Speichergröße der Bitmap beträgt Breite x Höhe x Bits pro Farbe. Ich glaube, Sie haben keine bestimmte Option verwendet, da Sie 4 Bytes pro Pixel verwenden (Rot 1 Byte, Grün 1 Byte, Blau 1 Byte, Alpha 1 Byte). Also: 960 * 926 * 4 = 3555840 Bytes.

Über deinen OOM: Was mir nicht so bekannt vorkommt ist:

  

Erzwingen der Sammlung von SoftReferences für 3555856-Byte-Zuweisung

Wo speichern Sie die zugewiesene Bitmap? Soft-Referenzen sollten auf Android vermieden werden.

    
Mimmo Grottoli 03.05.2016 12:19
quelle
1

Nach dem Vorschlag von Gabe Sechan würde ich empfehlen, eine Website wie makeappicon zu verwenden, mit der Sie jedes Bild, das zu groß ist, automatisch skalieren können . Es ist ein nützliches Tool, obwohl Android diese Skalierungsprobleme für Sie behandeln sollte.

Mimmo Grottoli hat recht, was die ARGB-Bytes angeht, also muss ich mir da, soweit ich das beurteilen kann, keine Sorgen machen.

Der Grund, warum Sie diesen Fehler am wahrscheinlichsten haben, ist ein bedeutender Speicherverlust, der beim Erstellen (und nicht beim Zerstören) von Bitmaps eine Rolle spielt, die ich vor einiger Zeit aus einem Steg-Projekt gelernt habe.

Um diesen Speicher zu bereinigen, können Sie die onDestroy() -Methode für Ihre Aktivität / Ihr Fragment überschreiben, oder Sie können dies bei Bedarf manuell tun.

%Vor%

Ich hoffe, er hat dir geholfen.

    
Nicolas Gonzalez 04.05.2016 15:06
quelle
0

Es ist besser, Bibliotheken wie Glide oder Picasso für alle Bildoperationen zu verwenden (Decodierung, Größenanpassung, Download usw.):

Ersetzen Sie den Pfad durch den Pfad des lokalen Ordners oder die Server-URL

Abhängigkeit :

%Vor%

Laden Sie das Bild mit Glide

%Vor%     
Pehlaj 05.05.2016 07:41
quelle