it-swarm.it

Quando System.gc () fa qualcosa?

So che la garbage collection è automatizzata in Java. Ma ho capito che se chiami System.gc() nel tuo codice, la JVM potrebbe o meno decidere di eseguire la garbage collection a quel punto. Come funziona esattamente? Su quali basi/parametri decide esattamente la JVM di fare (o non fare) un GC quando vede System.gc()?

Ci sono esempi nel qual caso è una buona idea inserire questo nel tuo codice?

111
harry

In pratica di solito decide di fare una garbage collection. La risposta varia in base a molti fattori, come ad esempio la JVM in esecuzione, la modalità in cui si trova e l'algoritmo di garbage collection che sta utilizzando.

Non dipenderei da questo nel tuo codice. Se la JVM sta per lanciare un OutOfMemoryError, chiamare System.gc () non lo fermerà, perché il garbage collector tenterà di liberare il più possibile prima che raggiunga l'estremo. L'unica volta che l'ho visto usato in pratica è negli IDE in cui è collegato a un pulsante su cui un utente può fare clic, ma anche lì non è terribilmente utile.

58
jodonnell

L'unico esempio che mi viene in mente dove ha senso chiamare System.gc () è quando si profila un'applicazione per cercare possibili perdite di memoria. Credo che i profiler chiamino questo metodo appena prima di scattare un'istantanea della memoria.

29

Il Java Language Specification non garantisce che la JVM avvierà un GC quando si chiama System.gc(). Questo è il motivo per cui "può o meno decidere di fare un GC a quel punto".

Ora, se guardi codice sorgente OpenJDK , che è la spina dorsale di Oracle JVM, vedrai che una chiamata a System.gc() avvia un ciclo GC. Se usi un'altra JVM, come J9, devi controllare la loro documentazione per scoprire la risposta. Ad esempio, la JVM di Azul ha un garbage collector che funziona continuamente, quindi una chiamata a System.gc() non farà nulla

Qualche altra risposta menziona l'avvio di un GC in JConsole o VisualVM. Fondamentalmente, questi strumenti effettuano una chiamata remota a System.gc().

Di solito, non si desidera avviare un ciclo di garbage collection dal codice, poiché confonde con la semantica della propria applicazione. La tua applicazione svolge alcune attività aziendali, la JVM si occupa della gestione della memoria. Dovresti tenere separate queste preoccupazioni (non fare in modo che la tua applicazione gestisca un po 'di memoria, concentrati sul business).

Tuttavia, ci sono alcuni casi in cui una chiamata a System.gc() potrebbe essere comprensibile. Considera, ad esempio, i microbenchmark. Nessuno vuole che avvenga un ciclo GC nel mezzo di un microbenchmark. Quindi è possibile attivare un ciclo GC tra ciascuna misurazione per assicurarsi che ogni misurazione inizi con un heap vuoto.

24
Pierre Laporte

Non hai alcun controllo su GC in Java - decide VM. Non ho mai incontrato un caso in cui System.gc() è necessario . Poiché una System.gc() chiama semplicemente SUGGERIMENTI che VM esegue una garbage collection e fa anche una FULL collection (vecchie e nuove generazioni in un heap multi-generazionale), allora può effettivamente causare il consumo di PIÙ cicli della CPU del necessario.

In alcuni casi, può avere senso suggerire a VM di eseguire una raccolta completa ORA, poiché potresti sapere che l'applicazione rimarrà inattiva per i prossimi minuti prima che si verifichi un sollevamento pesante. Ad esempio, subito dopo l'inizializzazione di molti oggetti temporanei durante l'avvio dell'applicazione (ovvero, ho appena memorizzato nella cache una tonnellata di informazioni e so che non avrò molta attività per un minuto o giù di lì). Pensa a un IDE come Eclipse che si avvia - fa molto per inizializzare, quindi forse subito dopo l'inizializzazione ha senso fare un gc completo a quel punto.

23
DustinB

Devi stare molto attento se chiami System.gc(). Chiamarlo può aggiungere problemi di prestazioni non necessari all'applicazione e non è garantito che esegua effettivamente una raccolta. In realtà è possibile disabilitare esplicito System.gc() tramite l'argomento Java argomento -XX:+DisableExplicitGC.

Consiglio vivamente di leggere i documenti disponibili su Java HotSpot Garbage Collection per maggiori dettagli sulla raccolta dei rifiuti.

17

System.gc() è implementato dalla VM e ciò che fa è specifico dell'implementazione. L'implementatore potrebbe semplicemente tornare e non fare nulla, per esempio.

Per quanto riguarda quando emettere una raccolta manuale, l'unica volta in cui potresti voler fare questo è quando abbandoni una grande raccolta che contiene un sacco di raccolte più piccole - un Map<String,<LinkedList>> per esempio - e vuoi provare a fare il colpo perfetto allora e lì, ma per la maggior parte, non dovresti preoccupartene. Il GC lo sa meglio di te - purtroppo - il più delle volte.

10
Patrick

Se si utilizzano buffer di memoria diretti, JVM non esegue il GC per te anche se la memoria diretta è insufficiente.

Se si chiama ByteBuffer.allocateDirect() e si ottiene un OutOfMemoryError, è possibile trovare questa chiamata corretta dopo aver attivato manualmente un GC.

8
Peter Lawrey

La maggior parte delle JVM avvia un GC (a seconda dell'opzione -XX: DiableExplicitGC e -XX: + ExplicitGCInvokesConcurrent). Ma le specifiche sono solo meno ben definite al fine di consentire implementazioni migliori in seguito.

La specifica necessita di chiarimenti: Bug # 6668279: (spec) System.gc () dovrebbe indicare che non consigliamo l'uso e non garantiamo il comportamento

Internamente il metodo gc viene utilizzato da RMI e NIO e richiedono l'esecuzione sincrona, che: questo è attualmente in discussione:

Bug # 5025281: Consenti a System.gc () di attivare raccolte complete simultanee (non stop-the-world)

5
eckes

Garbage Collection È buono in Java, se stiamo eseguendo il software codificato in Java in Desktop/laptop/server. Puoi chiamare System.gc() o Runtime.getRuntime().gc() in Java.

Basta notare che nessuna di quelle chiamate è garantita per fare nulla. Sono solo un suggerimento per jvm per eseguire Garbage Collector. Spetta alla JVM se esegue il GC o meno. Quindi, risposta breve: non sappiamo quando funziona. Risposta più lunga: JVM eseguirà gc se avesse tempo per quello.

Credo, lo stesso vale per Android. Tuttavia, ciò potrebbe rallentare il sistema.

2
Naveen

Normalmente, il VM eseguirà automaticamente una garbage collection prima di lanciare una OutOfMemoryException, quindi l'aggiunta di una chiamata esplicita non dovrebbe essere d'aiuto, tranne nel fatto che forse sposta l'hit di performance in un momento precedente.

Tuttavia, penso di aver riscontrato un caso in cui potrebbe essere rilevante. Non sono sicuro, poiché devo ancora verificare se ha qualche effetto:

Quando si mappa in memoria un file, credo che la chiamata map () generi un'eccezione IOException quando un blocco di memoria abbastanza grande non è disponibile. Una raccolta di rifiuti appena prima del file map () potrebbe aiutare a prevenirlo, credo. Cosa pensi?

2
Vashek

non possiamo mai forzare la raccolta dei rifiuti. System.gc sta solo suggerendo vm per la garbage collection, tuttavia, a che ora funziona il meccanismo, nessuno lo sa, come affermato dalle specifiche JSR.

2
lwpro2

C'è molto da dire nel prendere il tempo per testare le varie impostazioni di Garbage Collection, ma come è stato detto sopra di solito non è utile farlo.

Attualmente sto lavorando a un progetto che coinvolge un ambiente con memoria limitata e una quantità relativamente grande di dati - ci sono alcuni grandi pezzi di dati che spingono il mio ambiente al limite, e anche se sono stato in grado di ridurre l'utilizzo della memoria così che in teoria dovrebbe funzionare bene, otterrei comunque errori nello spazio dell'heap --- le opzioni GC dettagliate mi hanno mostrato che stava cercando di raccogliere i rifiuti, ma inutilmente. Nel debugger, ho potuto eseguire System.gc () e abbastanza sicuro che ci sarebbe "molta" memoria disponibile ... non un sacco di extra, ma abbastanza.

Di conseguenza, l'unica volta che la mia applicazione chiama System.gc () è quando sta per immettere il segmento di codice in cui verranno allocati i buffer di grandi dimensioni necessari per l'elaborazione dei dati e un test sulla memoria disponibile disponibile indica che non lo sono garantito per averlo. In particolare, sto osservando un ambiente da 1 GB in cui almeno 300 MB sono occupati da dati statici, con la maggior parte dei dati non statici correlati all'esecuzione, tranne quando i dati in elaborazione sono almeno 100-200 MB a la fonte. Fa tutto parte di un processo di conversione automatica dei dati, quindi i dati esistono tutti per periodi di tempo relativamente brevi nel lungo periodo.

Sfortunatamente, mentre sono disponibili informazioni sulle varie opzioni per l'ottimizzazione del Garbage Collector, sembra in gran parte un processo sperimentale e le specifiche di livello inferiore necessarie per capire come gestire queste situazioni specifiche non sono facilmente ottenibili.

Detto questo, anche se sto usando System.gc (), ho ancora continuato a ottimizzare i parametri della riga di comando e sono riuscito a migliorare il tempo di elaborazione complessivo della mia applicazione di un importo relativamente significativo, nonostante non sia riuscito a superare il ostacolo posto lavorando con i blocchi di dati più grandi. Detto questo, System.gc () è uno strumento .... uno strumento molto inaffidabile, e se non stai attento a come lo usi, vorrai che non funzionasse più spesso.

2
Kyune

In breve:

I parametri sono VM dipendente.

Esempio di utilizzo: non riesco a pensarne uno per le app di runtime/produzione, ma è utile eseguirlo per alcuni cablaggi di profilazione, come chiamare

// test run #1
test();
for (int i=0; i<10; i++) { 
// calling repeatedly to increase chances of a clean-up
  System.gc(); 
}
// test run #2
test();
1
mataal

Se vuoi sapere se viene chiamato System.gc(), puoi con il nuovo Java 7 aggiornamento 4 ricevere una notifica quando JVM esegue Garbage Collection.

Non sono sicuro al 100% che la classe GarbageCollectorMXBean sia stata introdotta in Java 7 aggiornamento 4, perché non sono riuscito a trovarlo nelle note di rilascio, ma ho trovato le informazioni nel sito javaperformancetuning . com

1
Shervin Asgari

Secondo Thinking in Java di Bruce Eckel, un caso d'uso per la chiamata esplicita System.gc () è quando si desidera forzare la finalizzazione, nella chiamata a - finalizza metodo.

0
Asterisk

Non riesco a pensare a un esempio specifico quando è bene eseguire GC esplicito.

In generale, l'esecuzione di GC esplicito può effettivamente causare più danni che benefici, perché un gc esplicito attiverà una raccolta completa, che impiega molto più tempo a passare attraverso ogni oggetto. Se questo esplicito gc viene chiamato ripetutamente, potrebbe facilmente portare a un'applicazione lenta poiché si impiega molto tempo a eseguire GC completi.

In alternativa, se si passa sopra l'heap con un analizzatore di heap e si sospetta che un componente della libreria chiami GC espliciti, è possibile disattivarlo aggiungendo: gc = -XX: + DisableExplicitGC ai parametri JVM.

0
zxcv

mentre system.gc funziona, fermerà il mondo: tutte le respones vengono fermate in modo che il garbage collector possa scansionare ogni oggetto per verificare se è necessario eliminarlo. se l'applicazione è un progetto Web, tutte le richieste vengono arrestate fino al termine di gc, e ciò comporterà il mancato funzionamento del progetto Web in un monent.

0
fleture