2012-05-20 10 views
28

Sono abbastanza nuovo per lo sviluppo di Android e non riesco a capire l'eccezione Java Out of Memory. So che significa che la mia app ha superato il budget della VM, ma dopo aver cercato su Google molte volte non riesco ancora a cogliere questo concetto. Ho paura che la mia app utilizzi troppa memoria perché ho sei selettori di pulsanti per schermo con due bitmap per ciascun selettore che sono circa 20 kb ciascuno secondo la scheda delle proprietà. Sul mio G2x root ho impostato il budget della VM su 12mb, ho riavviato il mio telefono e ho eseguito la mia app senza problemi. Sto relegando i drawable su ogni onDestroy() e accennando al GC di correre anche qui. Dopo aver usato l'app per un po 'nell'emulatore, faccio clic su "Cause GC" sullo schermo DDMS ei risultati sono ID = 1, Dimensione heap 6.133 MB, Assegnato 2.895 MB, Libero 3.238 MB,% utilizzato 47.20, # Oggetti 52.623.Dimensioni di heap di comprensione Android

Questo è dove non capisco cosa sta succedendo, il mio emulatore è impostato su 24MB di VM. Dov'è quel numero? Il vero problema che sto avendo è che se imposto l'emulatore su 16MB di VM, la mia app si arresta in modo anomalo sulla seconda attività con l'eccezione Memoria esaurita. Come mai non si blocca sul mio telefono con la VM impostata su 12 MB o sul mio vecchio telefono HTC Magic con 12 MB di VM stock? Credi anche che la mia app stia occupando troppa memoria? Non ho idea se quei numeri DDMS siano buoni o no. Grazie per il tuo tempo.

Per quanto riguarda il mio codice, ho ogni immagine specificata nei layout XML. Non faccio nulla di programmatico con loro tranne che per aggiungere gli ascoltatori a loro. Ho trovato questo pezzo di codice su qui e ho aggiunto ad ogni attività che ho ...

@Override 
protected void onDestroy() { 
    super.onDestroy(); 

    unbindDrawables(findViewById(R.id.myRootLayout)); 
    System.gc(); 
} 

private void unbindDrawables(View view) { 
    if (view.getBackground() != null) { 
     view.getBackground().setCallback(null); 
    } 
    if (view instanceof ViewGroup && !(view instanceof AdapterView)) { 
     for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) { 
      unbindDrawables(((ViewGroup) view).getChildAt(i)); 
     } 
     ((ViewGroup) view).removeAllViews(); 
    } 
} 

Altrimenti non faccio altro che aggiungere onClickListeners ai pulsanti che hanno gli sfondi PNG. Mi piacerebbe imparare come specificare gli sfondi dei pulsanti in modo programmatico, ma ho bisogno di avere le funzioni di selettore come messa a fuoco, in stampa, non focalizzato ma premuto ecc. Per far cambiare lo sfondo dei pulsanti in base all'interazione dell'utente. Ho esaminato i documenti a riguardo ma sembra schiacciante, ecco perché ho pensato di iniziare da qui con le basi della gestione degli heap e di lavorare fino a specificare i selettori nel codice. Questo potrebbe non avere senso, ma c'è una quantità "sana" di allocazione di memoria che un'app potrebbe allocare senza avvicinarsi all'eccezione di memoria insufficiente? Ad esempio, se un'app allocata 6 MB dovrebbe essere soddisfacente, ma 8 MB lo spingono, ci sono limiti del genere nell'allocazione della memoria? Grazie ancora Alex Lockwood per la tua risposta leggerò e rileggerò di nuovo fino a quando questa roba non ha senso per me

risposta

50

Quando imposti il ​​budget della macchina virtuale sul tuo emulatore/dispositivo, quello che stai facendo è dire all'heap la dimensione massima consentita. In fase di runtime, l'heap cresce in modo dinamico in termini di dimensioni poiché la macchina virtuale Dalvik richiede la memoria di sistema dal sistema operativo. La VM Dalvik inizia in genere allocando un heap relativamente piccolo. Quindi, dopo l'esecuzione di ogni GC, controlla la quantità di memoria heap disponibile. Se il rapporto tra heap libero e heap totale è troppo piccolo, la VM di Dalvik aggiungerà più memoria all'heap (fino alla dimensione massima di heap configurata).

Detto questo, il motivo per cui non viene visualizzato "24 mb" sullo schermo del DDMS è perché l'heap non ha raggiunto la dimensione massima. Ciò consente ad Android di sfruttare al meglio la già piccola quantità di memoria disponibile sui dispositivi palmari.

Per quanto riguarda il motivo per cui l'applicazione si blocca sull'emulatore e non sul telefono, sembra strano (sei sicuro che i numeri siano corretti?). Si tenga presente, tuttavia, che la memoria è gestita in modo dinamico e che l'utilizzo totale della memoria è determinato in base a un numero di fattori esterni (velocità/frequenza in cui viene eseguita la raccolta dei dati inutili, ecc.).

Infine, per le ragioni di cui sopra, sarebbe difficile dire con certezza quanto l'applicazione gestisca la memoria in base alla singola riga di informazioni fornita in precedenza. Avremmo davvero bisogno di vedere un po 'del tuo codice.OutOfMemoryError s sono sicuramente vale la pena di preoccuparsi, quindi, vorrei sicuramente esaminare l'utilizzo della memoria dell'applicazione. Una cosa che potresti considerare è di campionare le immagini bitmap in fase di esecuzione con le chiamate a inSampleSize utilizzando la classe BitmapFactory. Questo può aiutare a ridurre la quantità di memoria richiesta per caricare i tuoi bitmap disegnabili. O quello o potresti ridurre la risoluzione dei tuoi drawable (anche se 20 kb mi sembrano buoni).

+3

+1, risposta molto informativa! –

+0

Grazie mille! Ho imparato molto da questo. Aggiungo alcune informazioni alla fine della domanda –

+0

Rifiuta il commento "20 kb ciascuna suona bene" - AFAIK, non importa quale sia la * dimensione del file * (che sarà più piccola per le immagini che comprimono meglio), conta ciò che * DIMENSIONI * sono; in memoria, per full color, prenderà 4B per pixel, giusto? Quindi, è importante ridimensionare l'immagine quando la si carica [documenti android - Carica una versione ridotta in memoria], in base alla dimensione effettiva necessaria, per il dispositivo corrente. – ToolmakerSteve

16

Anche se l'applicazione non raggiunge il limite di heap "24mb" (varia all'interno dei dispositivi), è possibile che si verifichino ancora arresti anomali poiché Android impiega un po 'di tempo a far crescere lo spazio heap per l'app.

Nella mia situazione stavo creando e scaricando diverse immagini in un breve lasso di tempo.

Molto spesso ricevevo OutOfMemoryError.

Sembra che Android non sia stato abbastanza veloce da far crescere lo spazio dell'heap per la mia app.

Credo di aver risolto questo problema utilizzando l'impostazione largeHeap nel file Manifest. Con questa impostazione, Android lascia più memoria libera ogni volta che cresce l'heap, riducendo al minimo la possibilità di raggiungere il limite corrente.

Non uso il limite 24mb ma questo conf largeHeap era abbastanza utile.

Hai solo bisogno di impostare largeHeap="true" sul tag applicazione del AndroidManifest.xml

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

Eppure, assicurarsi che si sta attenti quando si tratta di immagini, come @alex Lockwood consigliato.

+16

Usa largeHeap = "true" con la massima cura. Perché l'utilizzo di questo potrebbe influire negativamente sulla perfomance dell'app. Perché stai dicendo al sistema di aumentare il limite massimo di heap. Quando ciò accade, ci vorrà più tempo per la garbage collection. Se controlli il log puoi vedere che il tempo di pausa in GC sarà maggiore. Idealmente dovrebbe essere tra 2-5ms. In questo caso può variare anche fino a 30-45ms. Quindi non impostare la proprietà heap grande su true solo perché stai esaurendo la memoria. Usalo come l'ultimo passo. Altrimenti sarà un successo. –

+0

Infatti. Nel mio caso, ho a che fare con molte immagini di alta qualità dinamicamente e, prima di utilizzare l'opzione largeHeap, ho implementato il codice in: - carica immagini campionate - ridimensiona le immagini in modo perfetto - cancella le immagini inutilizzate dalla memoria - memorizzazione nella cache delle immagini in "disco" Avevo ancora problemi risolti solo con l'opzione largeHeap. Ancora, usalo solo dopo aver provato tutto il resto, come consigliato da @SanalVarghese. – tbraun

+0

Solo aggiungendo a questo, ho avuto un sacco di problemi con la memoria della mia app la sua dimensione aumenta notevolmente. Potrebbe non essere impostato insieme in modo efficiente a questo punto, ma avrebbe dovuto essere in grado di non-superare il limite di heep. Tuttavia non avrebbe mai rilasciato molte risorse. Per qualche motivo lo fa molto bene dopo aver applicato l'opzione largeHeap. Grazie mille. –