android - populares - related hashtags instagram




BitmapFactory OOM mi sta facendo impazzire (4)

1,6 MB di memoria mi sembrano tanti ma potrebbe essere il caso che la memoria sia così frammentata da non poter allocare un blocco così grande di memoria in una volta sola (tuttavia questo suona molto strano).

Una causa comune di OOM durante l'utilizzo delle risorse di immagine è quando si esegue la decompressione di immagini JPG, PNG, GIF con risoluzioni veramente elevate. Devi tenere a mente che tutti questi formati sono abbastanza compressi e occupano pochissimo spazio ma una volta caricate le immagini sul telefono, la memoria che useranno è qualcosa come width * height * 4 bytes . Inoltre, quando la decompressione entra in gioco, alcune altre strutture di dati ausiliari devono essere caricate per la fase di decodifica.

Ho fatto molte ricerche e so che molte altre persone stanno vivendo gli stessi problemi di memoria OOM con BitmapFactory . La mia app mostra solo una memoria totale disponibile di 4 MB utilizzando Runtime.getRuntime ().totalMemory() . Se il limite è 16 MB, allora perché la memoria totale non aumenta per lasciare spazio alla bitmap? Invece genera un errore.

Inoltre, non capisco che se ho Runtime.getRuntime().freeMemory() di memoria libera in base a Runtime.getRuntime().freeMemory() perché viene visualizzato un errore che dice "VM non ci permetterà di allocare 614400 byte"? Mi sembra che abbia molta memoria disponibile.

La mia app è completa tranne per questo problema, che scompare quando riavvio il telefono in modo che la mia app sia l'unica cosa in esecuzione. Sto utilizzando un HTC Hero per il test del dispositivo (Android 1.5).

A questo punto sto pensando che l'unico modo per aggirare questo è in qualche modo evitare di usare BitmapFactory .

Qualcuno ha qualche idea su questo o una spiegazione sul motivo per cui VM non allocherà 614 KB se ci sono 1,6 MB di memoria libera?


Anche se di solito non ha senso rilevare un errore perché solitamente vengono lanciati solo dal vm ma in questo caso particolare l'errore viene generato dal codice jni glue quindi è molto semplice gestire casi in cui non è possibile caricare l'immagine: solo cattura l'OutOfMemoryError.


Sembra che i problemi indicati nella risposta di Torid siano stati risolti nelle versioni più recenti di Android.

Tuttavia, se si utilizza una cache di immagini (una specializzata o anche solo una normale HashMap), è piuttosto facile ottenere questo errore creando una perdita di memoria.

Nella mia esperienza, se inavvertitamente trattieni i tuoi riferimenti Bitmap e crei una perdita di memoria, l'errore dell'OP (un riferimento ai metodi BitmapFactory e nativo) è quello che causerà il crash della tua app (fino a ICS - 14 e +?)

Per evitare ciò, fai in modo che tu "lasci andare" le tue Bitmap. Ciò significa utilizzare SoftReferences nell'ultimo livello della cache, in modo che Bitmap possa ricavarne i dati inutili. Questo dovrebbe funzionare, ma se si verificano ancora arresti anomali, puoi provare a contrassegnare esplicitamente alcune bitmap per la raccolta utilizzando bitmap.recycle() , ricorda di non restituire mai una bitmap da utilizzare nella tua app se bitmap.isRecycled() .

Per LinkedHashMaps , LinkedHashMaps è un ottimo strumento per implementare facilmente strutture cache piuttosto buone, soprattutto se si combinano riferimenti hard e soft come in questo esempio (riga 308) ... ma l'uso di riferimenti rigidi è anche il modo in cui è possibile ottenere in memoria situazioni di perdita se si incasina.


[Nota che (come illustrato da CommonsWare in basso) l'intero approccio in questa risposta si applica solo fino al 2.3.x (Gingerbread) incluso. A partire da Honeycomb I dati bitmap sono allocati nell'heap della VM.]

I dati bitmap non sono allocati nell'heap della VM. C'è un riferimento ad esso nell'heap della VM (che è piccolo), ma i dati reali sono allocati nell'heap nativo dalla libreria grafica Skia sottostante.

Sfortunatamente, mentre la definizione di BitmapFactory.decode ... () dice che restituisce null se i dati dell'immagine non possono essere decodificati, l'implementazione di Skia (o piuttosto la colla JNI tra il codice Java e Skia) registra il messaggio che sei vedendo ("VM non ci permetterà di allocare xxxx byte") e quindi lancia un'eccezione OutOfMemory con il messaggio fuorviante "dimensione bitmap supera il budget della VM".

Il problema non è nell'heap della VM ma piuttosto nell'heap nativo. L'heap nativo è condiviso tra le applicazioni in esecuzione, quindi la quantità di spazio libero dipende da quali altre applicazioni sono in esecuzione e dal loro utilizzo di bitmap. Ma, dato che BitmapFactory non tornerà, hai bisogno di un modo per capire se la chiamata avrà successo prima di farcela.

Esistono routine per monitorare la dimensione dell'heap nativo (vedere i metodi getNative della classe Debug). Tuttavia, ho trovato che getNativeHeapFreeSize () e getNativeHeapSize () non sono affidabili. Quindi in una delle mie applicazioni che crea dinamicamente un gran numero di bitmap faccio quanto segue.

La dimensione dell'heap nativo varia in base alla piattaforma. Quindi all'avvio, controlliamo la dimensione massima dell'heap della VM consentita per determinare la dimensione massima consentita dell'heap nativo. [I numeri magici sono stati determinati testando su 2.1 e 2.2 e potrebbero essere diversi su altri livelli API.]

long mMaxVmHeap     = Runtime.getRuntime().maxMemory()/1024;
long mMaxNativeHeap = 16*1024;
if (mMaxVmHeap == 16*1024)
     mMaxNativeHeap = 16*1024;
else if (mMaxVmHeap == 24*1024)
     mMaxNativeHeap = 24*1024;
else
    Log.w(TAG, "Unrecognized VM heap size = " + mMaxVmHeap);

Quindi, ogni volta che dobbiamo chiamare BitmapFactory, la chiamata viene preceduta da un controllo del modulo.

long sizeReqd        = bitmapWidth * bitmapHeight * targetBpp  / 8;
long allocNativeHeap = Debug.getNativeHeapAllocatedSize();
if ((sizeReqd + allocNativeHeap + heapPad) >= mMaxNativeHeap)
{
    // Do not call BitmapFactory…
}

Si noti che heapPad è un numero magico per tenere conto del fatto che a) il reporting delle dimensioni dell'heap nativo è "soft" e b) vogliamo lasciare dello spazio nell'heap nativo per altre applicazioni. Al momento stiamo lavorando con un pad 3 * 1024 * 1024 (cioè 3Mbytes).





out-of-memory