È possibile forzare la garbage collection in Java, anche se è difficile da fare? Conosco System.gc();
e Runtime.gc();
suggeriscono solo di fare GC. Come posso forzare GC?
È possibile forzare la garbage collection in Java, anche se è difficile da fare? Conosco System.gc();
e Runtime.gc();
suggeriscono solo di fare GC. Come posso forzare GC?
Risposte:
La tua migliore opzione è quella di chiamare System.gc()
che è semplicemente un suggerimento per il garbage collector che vuoi che faccia una raccolta. Non c'è modo di forzare e la raccolta immediata anche se il garbage collector non è deterministico.
non-deterministic == trouble
GC.Collect()
non raccoglie. In Java gc()
fa.
La libreria jlibs ha una buona classe di utilità per la garbage collection . Puoi forzare la garbage collection usando un piccolo trucco con gli oggetti WeakReference .
RuntimeUtil.gc () dai jlibs:
/**
* This method guarantees that garbage collection is
* done unlike <code>{@link System#gc()}</code>
*/
public static void gc() {
Object obj = new Object();
WeakReference ref = new WeakReference<Object>(obj);
obj = null;
while(ref.get() != null) {
System.gc();
}
}
PhantomReference
con a ReferenceQueue
e poi verrai avvisato dopo la finalizzazione, ma ancora prima della pulizia. Infine, anche se hai rilevato con successo che la memoria per questo oggetto è stata recuperata, significherebbe molto poco in un GC generazionale come HotSpot. Di solito coinciderebbe con la pulizia delle giovani generazioni.
System.gc(); System.gc();
, ma sarebbe sicuramente interessante sapere se ha mai funzionato meglio di così. In effetti, basta stampare quante volte è stato chiamato System.gc()
. La possibilità di raggiungere mai 2 è piuttosto scarsa.
Il modo migliore (se non solo) per forzare un GC sarebbe quello di scrivere una JVM personalizzata. Credo che i Garbage Collector siano collegabili, quindi probabilmente potresti semplicemente scegliere una delle implementazioni disponibili e modificarla.
Nota: questa NON è una risposta facile.
Utilizzando l' interfaccia Java ™ Virtual Machine Tool (JVM TI) , la funzione
jvmtiError ForceGarbageCollection(jvmtiEnv* env)
"Forza la VM a eseguire una garbage collection". JVM TI fa parte della JavaTM Platform Debugger Architecture (JPDA) .
SÌ , è quasi possibile costringerti a chiamare metodi nello stesso ordine e allo stesso tempo questi sono:
System.gc ();
System.runFinalization ();
anche se è solo un oggetto per ripulire contemporaneamente l'uso di questi due metodi, forzare il garbage collector a utilizzare il finalise()
metodo dell'oggetto non raggiungibile liberando la memoria assegnata e facendo ciò che il finalize()
metodo afferma.
TUTTAVIA è una pratica terribile usare il Garbage Collector perché il suo utilizzo potrebbe introdurre un sovraccarico nel software che potrebbe essere anche peggio che in memoria, il Garbage Collector ha il suo thread che non è possibile controllare più a seconda di l'algoritmo usato da gc potrebbe richiedere più tempo ed è considerato molto inefficiente, dovresti controllare il tuo software se è peggio con l'aiuto di gc perché è sicuramente rotto, una buona soluzione non deve dipendere da gc.
NOTA: solo per tenere a mente questo funzionerà solo se nel metodo finalize non è una riassegnazione dell'oggetto, se ciò accade l'oggetto rimarrà in vita e avrà una resurrezione che è tecnicamente possibile.
gc()
è solo un suggerimento per eseguire una garbage collection. runFinalizers()
esegue solo i finalizzatori su oggetti "che sono stati trovati scartati". Se il gc non funzionasse effettivamente, potrebbero non esserci oggetti del genere ...
Nella documentazione per OutOfMemoryError dichiara che non verrà generato a meno che la VM non abbia recuperato la memoria a seguito di una garbage collection completa. Quindi se continui ad allocare memoria fino a quando non ricevi l'errore, avrai già forzato una garbage collection completa.
Presumibilmente la domanda che volevi davvero porre era "come posso recuperare il ricordo che penso dovrei essere recuperato dalla raccolta dei rifiuti?"
Per richiedere manualmente GC (non da System.gc ()):
.gc è un candidato all'eliminazione nelle versioni future - un tecnico Sun ha commentato che forse meno di venti persone al mondo sanno effettivamente come usare .gc () - Ho lavorato un po 'ieri sera per alcune ore su un argomento centrale / critico struttura dei dati che utilizza i dati generati da SecureRandom, in qualche posto appena oltre 40.000 oggetti, la VM rallenterebbe come se avesse esaurito i puntatori. Chiaramente si stava soffocando su tabelle di puntatori a 16 bit e presentava un comportamento classico di "macchine difettose".
Ho provato -Xms e così via, ho continuato a girare un po 'fino a quando non sarebbe arrivato a circa 57, xxx qualcosa. Quindi eseguirà gc andando da diciamo 57.127 a 57.128 dopo un gc () - a circa il ritmo di code-bloat al campo Easy Money.
Il tuo progetto ha bisogno di una rielaborazione fondamentale, probabilmente di un approccio a finestra scorrevole.
È possibile attivare un GC dalla riga di comando. Questo è utile per batch / crontab:
jdk1.7.0/bin/jcmd <pid> GC.run
Vedi:
La specifica JVM non dice nulla di specifico sulla garbage collection. Per questo motivo, i fornitori sono liberi di implementare GC a modo loro.
Quindi questa vaghezza provoca incertezza nel comportamento della raccolta dei rifiuti. Dovresti controllare i dettagli della tua JVM per conoscere gli approcci / algoritmi di garbage collection. Inoltre ci sono opzioni per personalizzare anche il comportamento.
Se devi forzare la raccolta dei rifiuti, forse dovresti considerare come gestisci le risorse. Stai creando oggetti di grandi dimensioni che persistono nella memoria? Stai creando oggetti di grandi dimensioni (ad es. Classi grafiche) che hanno Disposable
un'interfaccia e non chiamano dispose()
quando hai finito? Stai dichiarando qualcosa a livello di classe di cui hai bisogno solo all'interno di un singolo metodo?
Sarebbe meglio se descrivi il motivo per cui hai bisogno della raccolta dei rifiuti. Se si utilizza SWT, è possibile disporre risorse come Image
e Font
per liberare memoria. Per esempio:
Image img = new Image(Display.getDefault(), 16, 16);
img.dispose();
Ci sono anche strumenti per determinare risorse non poste.
Se stai esaurendo la memoria e ne OutOfMemoryException
stai ottenendo una , puoi provare ad aumentare la quantità di spazio heap disponibile per java avviando il programma con java -Xms128m -Xmx512m
anziché semplicemente java
. Questo ti darà una dimensione iniziale dell'heap di 128 Mb e un massimo di 512 Mb, che è molto più di 32 Mb / 128 Mb standard.
java -Xms512M -Xmx1024M
Un'altra opzione è quella di non creare nuovi oggetti.
Il pool di oggetti è assente per ridurre la necessità di GC in Java.
Il pool di oggetti in genere non sarà più veloce della creazione di oggetti (specialmente per oggetti leggeri) ma è più veloce di Garbage Collection. Se hai creato 10.000 oggetti e ogni oggetto era di 16 byte. Sono 160.000 byte che GC deve recuperare. D'altra parte, se non sono necessari tutti i 10.000 contemporaneamente, è possibile creare un pool per riciclare / riutilizzare gli oggetti che elimina la necessità di costruire nuovi oggetti ed elimina la necessità di vecchi oggetti GC.
Qualcosa del genere (non testato). E se vuoi che sia thread-safe, puoi scambiare il LinkedList con un ConcurrentLinkedQueue.
public abstract class Pool<T> {
private int mApproximateSize;
private LinkedList<T> mPool = new LinkedList<>();
public Pool(int approximateSize) {
mApproximateSize = approximateSize;
}
public T attain() {
T item = mPool.poll();
if (item == null) {
item = newInstance();
}
return item;
}
public void release(T item) {
int approxSize = mPool.size(); // not guaranteed accurate
if (approxSize < mApproximateSize) {
recycle(item);
mPool.add(item);
} else if (approxSize > mApproximateSize) {
decommission(mPool.poll());
}
}
public abstract T newInstance();
public abstract void recycle(T item);
public void decommission(T item) { }
}
Su OracleJDK 10 con G1 GC, una singola chiamata System.gc()
farà sì che GC ripulisca la vecchia raccolta. Non sono sicuro che GC funzioni immediatamente. Tuttavia, GC non pulirà la Young Collection anche se System.gc()
viene chiamata più volte in un ciclo. Per ottenere GC per ripulire la Young Collection, è necessario allocare in un ciclo (ad esempio new byte[1024]
) senza chiamare System.gc()
. Chiamare System.gc()
per qualche motivo impedisce a GC di ripulire la Young Collection.
Davvero, non ti capisco. Ma per essere chiari su "Infinite Object Creation" intendevo dire che nel mio grande sistema c'è un pezzo di codice che crea oggetti che gestisce e vive nella memoria, in realtà non ho potuto ottenere questo pezzo di codice, solo un gesto !!
Questo è corretto, solo gesto. Hai praticamente le risposte standard già fornite da diversi poster. Prendiamolo uno per uno:
Esatto, non esiste un vero jvm - tale è solo una specifica, un mucchio di informatica che descrive un comportamento desiderato ... Di recente ho scavato nell'inizializzazione degli oggetti Java dal codice nativo. Per ottenere ciò che vuoi, l'unico modo è fare quello che viene chiamato annullamento aggressivo. Gli errori se commessi in modo errato sono così gravi che dobbiamo limitarci all'ambito originale della domanda:
La maggior parte dei poster qui presumono che tu stia dicendo che stai lavorando a un'interfaccia, se tale dovremmo vedere se ti viene consegnato l'intero oggetto o un oggetto alla volta.
Se non è più necessario un oggetto, è possibile assegnare null all'oggetto, ma se si sbaglia, viene generata un'eccezione puntatore null. Scommetto che puoi ottenere un lavoro migliore se usi NIO
Ogni volta che tu o io o chiunque altro riceviamo: " Per favore, ne ho bisogno orribilmente. " È un precursore quasi universale per la distruzione quasi totale di ciò su cui stai cercando di lavorare .... scrivici un piccolo codice di esempio, disinfettandolo da esso codice effettivo utilizzato e mostraci la tua domanda.
Non sentirti frustrato. Spesso ciò a cui si risolve è che il tuo dba sta usando un pacchetto acquistato da qualche parte e il design originale non è ottimizzato per enormi strutture di dati.
Questo è molto comune.
FYI
La chiamata al metodo System.runFinalizersOnExit (true) garantisce che i metodi del finalizzatore vengano chiamati prima della chiusura di Java. Tuttavia, questo metodo è intrinsecamente non sicuro ed è stato deprecato. Un'alternativa è aggiungere "hook di arresto" con il metodo Runtime.addShutdownHook.
Masarrat Siddiqui
Esiste un modo indiretto per forzare il Garbage Collector. Devi solo riempire l'heap con oggetti temporanei fino al momento in cui verrà eseguito Garbage Collector. Ho creato una classe che forza il garbage collector in questo modo:
class GarbageCollectorManager {
private static boolean collectionWasForced;
private static int refCounter = 0;
public GarbageCollectorManager() {
refCounter++;
}
@Override
protected void finalize() {
try {
collectionWasForced = true;
refCounter--;
super.finalize();
} catch (Throwable ex) {
Logger.getLogger(GarbageCollectorManager.class.getName()).log(Level.SEVERE, null, ex);
}
}
public int forceGarbageCollection() {
final int TEMPORARY_ARRAY_SIZE_FOR_GC = 200_000;
int iterationsUntilCollected = 0;
collectionWasForced = false;
if (refCounter < 2)
new GarbageCollectorManager();
while (!collectionWasForced) {
iterationsUntilCollected++;
int[] arr = new int[TEMPORARY_ARRAY_SIZE_FOR_GC];
arr = null;
}
return iterationsUntilCollected;
}
}
Uso:
GarbageCollectorManager manager = new GarbageCollectorManager();
int iterationsUntilGcExecuted = manager.forceGarbageCollection();
Non so quanto sia utile questo metodo, perché riempie costantemente heap, ma se si dispone di un'applicazione mission-critical che DEVE forzare GC - quando questo potrebbe essere il modo portatile Java per forzare GC.
Vorrei aggiungere qualcosa qui. Si prega di non Java che gira su macchine virtuali e non su macchine reali. La macchina virtuale ha il suo modo di comunicare con la macchina. Potrebbe variare da sistema a sistema. Ora quando chiamiamo il GC chiediamo alla Macchina Virtuale di Java di chiamare il Garbage Collector.
Poiché Garbage Collector è con Virtual Machine, non possiamo costringerlo a fare una pulizia lì e poi. Piuttosto che mettiamo in coda la nostra richiesta con il Garbage Collector. Dipende dalla macchina virtuale, dopo un determinato periodo di tempo (questo può cambiare da sistema a sistema, generalmente quando la memoria di soglia allocata alla JVM è piena) la macchina effettiva libererà spazio. : D
Il seguente codice è preso dal metodo assertGC (...). Cerca di forzare la raccolta non deterministica di immondizia.
List<byte[]> alloc = new ArrayList<byte[]>();
int size = 100000;
for (int i = 0; i < 50; i++) {
if (ref.get() == null) {
// Test succeeded! Week referenced object has been cleared by gc.
return;
}
try {
System.gc();
} catch (OutOfMemoryError error) {
// OK
}
try {
System.runFinalization();
} catch (OutOfMemoryError error) {
// OK
}
// Approach the jvm maximal allocatable memory threshold
try {
// Allocates memory.
alloc.add(new byte[size]);
// The amount of allocated memory is increased for the next iteration.
size = (int)(((double)size) * 1.3);
} catch (OutOfMemoryError error) {
// The amount of allocated memory is decreased for the next iteration.
size = size / 2;
}
try {
if (i % 3 == 0) Thread.sleep(321);
} catch (InterruptedException t) {
// ignore
}
}
// Test failed!
// Free resources required for testing
alloc = null;
// Try to find out who holds the reference.
String str = null;
try {
str = findRefsFromRoot(ref.get(), rootsHint);
} catch (Exception e) {
throw new AssertionFailedErrorException(e);
} catch (OutOfMemoryError err) {
// OK
}
fail(text + ":\n" + str);
Fonte (ho aggiunto alcuni commenti per chiarezza): Esempio di NbTestCase
È possibile provare a utilizzare Runtime.getRuntime().gc()
o utilizzare il metodo di utilità System.gc()
Nota: questi metodi non garantiscono GC. E il loro ambito di applicazione dovrebbe essere limitato a JVM piuttosto che gestirlo a livello di programmazione nell'applicazione.