Garbage collector in Android


108

Ho visto molte risposte Android che suggeriscono di chiamare il garbage collector in alcune situazioni.

È una buona pratica richiedere il garbage collector in Android prima di eseguire un'operazione che richiede molta memoria? In caso contrario, dovrei chiamarlo solo se ricevo un OutOfMemoryerrore?

Ci sono altre cose che dovrei usare prima di ricorrere al garbage collector?

Risposte:


144

Per le versioni precedenti alla 3.0 Honeycomb : Sì, chiama System.gc() .

Ho provato a creare bitmap, ma ottenevo sempre "VM out of memory error". Ma, quando ho chiamato per la System.gc()prima volta, è andato tutto bene.

Durante la creazione di bitmap, Android spesso non riesce con errori di memoria insufficiente e non tenta prima la raccolta dei rifiuti . Quindi, chiama System.gc()e hai abbastanza memoria per creare bitmap.

Se si creano oggetti, penso che System.gcverrà chiamato automaticamente se necessario, ma non per la creazione di bitmap. Semplicemente fallisce.

Quindi consiglio di chiamare manualmente System.gc()prima di creare bitmap.


39
Questo perché pre-honeycomb, i dati bitmap non vengono memorizzati nella VM e quindi non attiveranno il GC. Non dovrebbe essere un problema in Honeycomb e versioni successive.
Timmmm

2
@Timmmm ma in realtà era un mio problema, ho appena impostato largeheap su true.
Lei Leyba

118

In generale, in presenza di un garbage collector, non è mai buona norma chiamare manualmente il GC. Un GC è organizzato intorno ad algoritmi euristici che funzionano meglio se lasciati a se stessi. Chiamare manualmente il GC spesso riduce le prestazioni.

Occasionalmente , in alcune situazioni relativamente rare, si può scoprire che un particolare GC sbaglia e una chiamata manuale al GC può quindi migliorare le cose, dal punto di vista delle prestazioni. Questo perché non è realmente possibile implementare un GC "perfetto" che gestirà la memoria in modo ottimale in tutti i casi. Tali situazioni sono difficili da prevedere e dipendono da molti sottili dettagli di implementazione. La "buona pratica" è lasciare che il GC funzioni da solo; una chiamata manuale al GC è l'eccezione, che dovrebbe essere prevista solo dopo che un problema di prestazioni effettivo è stato debitamente assistito.


8
+1 per una buona risposta indipendente dalla piattaforma. In attesa di vedere se qualcuno fornisce una risposta specifica per Android prima di scegliere.
hpique

8
Sono d'accordo con quello che hai scritto se consenti a "prestazioni" di significare qualcosa di più generale dell'efficienza della CPU. Su un dispositivo Android, la percezione delle prestazioni dell'utente è fondamentale. Lo sviluppatore potrebbe preferire eseguire il GC mentre l'utente preme i pulsanti, ad esempio, in modo che l'utente non sia a conoscenza del GC.
Presidente James K. Polk,

5
Spesso è importante nei giochi che il GC non venga eseguito mentre il gioco è in esecuzione (ciò richiede che tutti gli oggetti siano pre-creati e riciclati o simili), ma quando il gioco è in pausa è un buon momento per GC.
Pat

4
Pre-nido d'ape, i dati bitmap non vengono archiviati nella memoria della VM. Il sistema non rileverà quando hai usato troppa memoria non VM a causa di bitmap ed eseguirà il GC (che eseguirà i Bitmap.finalize()metodi che liberano la memoria non VM). Pertanto, in questo caso, dovresti andare oltre la testa del GC ed eseguire Bitmap.recycle()o System.gc()dove appropriato. Ma solo pre-favo.
Timmmm

1
@ThomasPornin - D'altra parte, come programmatore di applicazioni, sai qualcosa che il sistema operativo non conosce: i tempi in cui la tua app ora apporterà un cambiamento importante nel modo in cui usa la memoria e che sarebbe meno distruttivo l'esperienza dell'utente per fare una pausa ora, che in un momento arbitrario in futuro . Ciò significa che potrebbe essere opportuno effettuare chiamate poco frequenti , durante le principali transizioni di come viene utilizzata l'app. Questi sono rari nel senso che non si dovrebbe chiamare frequentemente GC, ma sono comuni in quanto quasi tutte le app significative hanno tali momenti noti per la progettazione.
ToolmakerSteve

26

La memoria insufficiente nell'applicazione Android è molto comune se non gestiamo correttamente la bitmap, la soluzione al problema sarebbe

if(imageBitmap != null) {
    imageBitmap.recycle();
    imageBitmap = null;
}
System.gc();
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 3;
imageBitmap = BitmapFactory.decodeFile(URI, options);
Bitmap  scaledBitmap = Bitmap.createScaledBitmap(imageBitmap, 200, 200, true);
imageView.setImageBitmap(scaledBitmap);

Nel codice sopra ho appena provato a riciclare la bitmap che ti permetterà di liberare lo spazio di memoria utilizzato, quindi la memoria esaurita potrebbe non accadere. Ho provato che ha funzionato per me.

Se il problema persiste, puoi aggiungere anche queste righe

BitmapFactory.Options options = new BitmapFactory.Options();
options.inTempStorage = new byte[16*1024];
options.inPurgeable = true;

per maggiori informazioni dai un'occhiata a questo link

https://web.archive.org/web/20140514092802/http://voices.yahoo.com/android-virtual-machine-vm-out-memory-error-7342266.html?cat=59


NOTA: A causa della momentanea "pausa" causato eseguendo gc, è non consigliabile farlo prima di ogni allocazione bitmap.

Il design ottimale è:

  1. Libera tutte le bitmap che non sono più necessarie , in base al if / recycle / nullcodice mostrato. (Crea un metodo per aiutarti in questo.)

  2. System.gc();

  3. Alloca le nuove bitmap.


19

Se ottieni un'eccezione OutOfMemoryError, di solito è troppo tardi per chiamare il garbage collector ...

Ecco una citazione dallo sviluppatore Android:

La maggior parte delle volte, la garbage collection si verifica a causa di tonnellate di piccoli oggetti di breve durata e alcuni garbage collector, come i garbage collector generazionali, possono ottimizzare la raccolta di questi oggetti in modo che l'applicazione non venga interrotta troppo spesso. Il garbage collector di Android purtroppo non è in grado di eseguire tali ottimizzazioni e la creazione di oggetti di breve durata in percorsi di codice critici per le prestazioni è quindi molto costosa per l'applicazione.

Quindi, a quanto mi risulta, non è necessario chiamare il gc. È meglio dedicare uno sforzo maggiore per evitare la creazione di oggetti non necessaria (come la creazione di oggetti all'interno di loop)


6
La citazione non può essere interpretata in altro modo? Forse il GC deve essere chiamato manualmente per raccogliere quegli oggetti prima che consumino troppa memoria.
hpique

@hgpc: non vedo come la citazione possa essere interpretata nel modo in cui suggerisci. Immagino che la documentazione sia una confessione, ammettendo che il loro GC è semplice; quando la memoria si esaurisce, viene eseguito un GC completo.
Presidente James K. Polk

Fare pieno uso di oggetti complessi e framework che utilizzano oggetti complessi tende a utilizzare meglio i tempi di sviluppo rispetto all'ottimizzazione prematura. Preoccuparsi dell'ottimizzazione è una trappola più facile in cui cadere per Android che per Enterprise Java, poiché inconsciamente continuiamo a pensare alle prestazioni durante la codifica di un'app mobile. Soprattutto perché gli sviluppatori di framework, che devono pensare alle prestazioni, trapelano quel punto di vista nella loro documentazione ufficiale quando non stanno attenti.
LateralFractal

9

Sembra System.gc()non funzionare su Art Android 6.0.1 Nexus 5x, quindi uso Runtime.getRuntime().gc();invece.


1
System.gc()è una funzione wrapper per Runtime.getRuntime().gc(). Vedi android.googlesource.com/platform/libcore/+/…
Nathan F.

Sì, dalla fonte e dalla documentazione sembra che siano la stessa cosa, ma in effetti System.gc()non funziona per me ma Runtime.getRuntime().gc()funziona!
Ivan il

7

La mia app gestisce molte immagini ed è morta con un OutOfMemoryError. Questo mi ha aiutato. Nel Manifest.xml Aggiungi

<application
....
   android:largeHeap="true"> 

9
A Google non piace questo
Pedro Paulo Amorim

1
@PedroPauloAmorim spiega perché?
Machado

2
Non usare largeHeap a meno che tu non sia sicuro di cosa stai facendo. L'utilizzo di grandi heap rende Garbage Collector molto più difficile perché deve eseguire il loop di molti dati spazzatura prima di cancellare la memoria.
Prakash

7

In generale, non dovresti chiamare GC esplicitamente con System.gc (). C'è anche la conferenza IO ( http://www.youtube.com/watch?v=_CruQY55HOk ) in cui spiegano cosa significa il registro delle pause del GC e in cui affermano anche di non chiamare mai System.gc () perché Dalvik lo sa meglio di te quando farlo.

D'altra parte, come accennato nelle risposte sopra, già il processo GC in Android (come tutto il resto) a volte è bacato. Ciò significa che gli algoritmi Dalvik GC non sono alla pari con Hotspot o JVM JRockit e potrebbero sbagliare in alcune occasioni. Una di queste occasioni è quando si allocano oggetti bitmap. Questo è complicato perché utilizza la memoria Heap e Non Heap e perché un'istanza libera di un oggetto bitmap su un dispositivo con limitazioni di memoria è sufficiente per darti un'eccezione OutOfMemory. Quindi chiamarlo dopo che non hai più bisogno di questa bitmap è generalmente suggerito da molti sviluppatori ed è persino considerato una buona pratica da alcune persone.

La pratica migliore è usare .recycle () su una bitmap poiché è ciò per cui è fatto questo metodo, poiché contrassegna la memoria nativa della bitmap come sicura da eliminare. Tieni presente che questo dipende molto dalla versione, il che significa che sarà generalmente richiesto sulle versioni precedenti di Android (Pre 3.0 credo) ma non sarà richiesto su quelle successive. Inoltre non farà molto male usarlo su versioni più recenti Ether (basta non farlo in un loop o qualcosa del genere). Il nuovo runtime ART è cambiato molto qui perché hanno introdotto una speciale "partizione" Heap per oggetti di grandi dimensioni, ma penso che non farà molto male farlo con ART ether.

Anche una nota molto importante su System.gc (). Questo metodo non è un comando a cui Dalvik (o le JVM) sono obbligate a rispondere. Considera più come dire alla macchina virtuale "Potresti per favore fare la raccolta dei rifiuti se non è una seccatura".



3

Direi di no, perché i documenti dello sviluppatore sull'utilizzo della RAM indicano:

...
GC_EXPLICIT

Un GC esplicito, come quando chiami gc () (che dovresti evitare di chiamare e fidarti invece del GC per l'esecuzione quando necessario).

...

Ho evidenziato la parte rilevante in grassetto.

Dai un'occhiata alla serie di YouTube, i modelli di prestazione Android - che vi mostrerà suggerimenti su come gestire l'utilizzo della memoria del vostro app (come l'utilizzo di Android ArrayMaps e SparseArrays invece di HashMaps).


3

Nota rapida per gli sviluppatori Xamarin .

Se desideri chiamare System.gc()nelle app Xamarin.Android dovresti chiamareJava.Lang.JavaSystem.Gc()


2

Non è necessario chiamare il garbage collector dopo un file OutOfMemoryError.

È Javadoc afferma chiaramente:

Thrown when the Java Virtual Machine cannot allocate an object because it is out of memory, and no more memory could be made available by the garbage collector.

Pertanto, il Garbage Collector ha già tentato di liberare memoria prima di generare l'errore, ma non è riuscito.


8
Il Javadoc Android non lo afferma e molto probabilmente la sua implementazione è diversa. d.android.com/reference/java/lang/OutOfMemoryError.html
hpique

Hai ragione che questo non si applica su Android. Ma poi di nuovo non puoi gestire OOE in runtime Ether, quindi non puoi fare molto al riguardo anche se questo era / non era vero.
Igor Čordaš
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.