C'è un modo per liberare memoria in Java, simile alla free()
funzione di C ? Oppure impostare l'oggetto su null e fare affidamento su GC l'unica opzione?
C'è un modo per liberare memoria in Java, simile alla free()
funzione di C ? Oppure impostare l'oggetto su null e fare affidamento su GC l'unica opzione?
Risposte:
Java utilizza la memoria gestita, quindi l'unico modo per allocare memoria è usando l' new
operatore, e l'unico modo per poter deallocare la memoria è affidarsi al garbage collector.
Questo white paper sulla gestione della memoria (PDF) può aiutare a spiegare cosa sta succedendo.
Puoi anche chiamare System.gc()
per suggerire che Garbage Collector venga eseguito immediatamente. Tuttavia, Java Runtime prende la decisione finale, non il codice.
Secondo la documentazione Java ,
La chiamata al metodo gc suggerisce che la Java Virtual Machine impieghi sforzi per riciclare oggetti inutilizzati al fine di rendere disponibile la memoria che occupano attualmente per un rapido riutilizzo. Quando il controllo ritorna dalla chiamata del metodo, Java Virtual Machine ha fatto il possibile per recuperare spazio da tutti gli oggetti scartati.
System.gc()
tutto.
Nessuno sembra aver menzionato l'impostazione esplicita di riferimenti a oggetti null
, che è una tecnica legittima per "liberare" la memoria che potresti voler prendere in considerazione.
Ad esempio, supponiamo che tu abbia dichiarato List<String>
a all'inizio di un metodo che è cresciuto in dimensioni per essere molto grande, ma è stato richiesto solo fino a metà del metodo. A questo punto è possibile impostare il riferimento Elenco su null
per consentire al garbage collector di potenzialmente recuperare questo oggetto prima del completamento del metodo (e comunque il riferimento non rientra nell'ambito).
Si noti che raramente utilizzo questa tecnica in realtà, ma vale la pena considerare quando si tratta di strutture di dati molto grandi.
System.gc();
Esegue il Garbage Collector.
La chiamata al metodo gc suggerisce che la Java Virtual Machine impieghi sforzi per riciclare oggetti inutilizzati al fine di rendere disponibile la memoria che occupano attualmente per un rapido riutilizzo. Quando il controllo ritorna dalla chiamata del metodo, la Java Virtual Machine ha fatto il possibile per recuperare spazio da tutti gli oggetti scartati.
Non consigliato.
Modifica: ho scritto la risposta originale nel 2009. Ora è il 2015.
I raccoglitori di immondizia sono migliorati costantemente negli ultimi 20 anni circa di Java. A questo punto, se stai chiamando manualmente il Garbage Collector, potresti prendere in considerazione altri approcci:
* "Mi affido personalmente alle variabili di annullamento come segnaposto per la futura corretta eliminazione. Ad esempio, mi prendo il tempo di annullare tutti gli elementi di un array prima di eliminare effettivamente (rendendo nullo) l'array stesso."
Questo non è necessario. Il modo in cui funziona il GC Java è che trova oggetti che non hanno alcun riferimento a loro, quindi se ho un oggetto x con un riferimento (= variabile) che lo punta, il GC non lo cancellerà, perché c'è un riferimento a quell'oggetto:
a -> x
Se si annulla a quanto segue:
a -> null
x
Quindi ora x non ha un riferimento che lo punta e verrà eliminato. La stessa cosa accade quando si imposta a per fare riferimento a un oggetto diverso da x.
Quindi se hai un array arr che fa riferimento agli oggetti x, ye z e una variabile a che fa riferimento all'array sembra che:
a -> arr -> x
-> y
-> z
Se si annulla a quanto segue:
a -> null
arr -> x
-> y
-> z
Quindi il GC trova arr come non avere alcun riferimento impostato su di esso e lo elimina, il che ti dà questa struttura:
a -> null
x
y
z
Ora il GC trova x, yey e li elimina pure. Annullare ogni riferimento nell'array non migliorerà nulla, utilizzerà solo il tempo e lo spazio della CPU nel codice (detto questo, non danneggerà ulteriormente di così. Il GC sarà comunque in grado di funzionare come dovrebbe ).
Un motivo valido per voler liberare memoria da qualsiasi programma (java o no) è rendere disponibile più memoria ad altri programmi a livello di sistema operativo. Se la mia applicazione java utilizza 250 MB, potrei volerlo forzare a 1 MB e rendere i 249 MB disponibili per altre app.
Per estendere la risposta e il commento di Yiannis Xanthopoulos e Hot Licks (scusate, non posso ancora commentare!), È possibile impostare le opzioni VM come questo esempio:
-XX:+UseG1GC -XX:MinHeapFreeRatio=15 -XX:MaxHeapFreeRatio=30
Nel mio jdk 7 questo rilascerà quindi la memoria VM inutilizzata se oltre il 30% dell'heap diventa libero dopo GC quando la VM è inattiva. Probabilmente dovrai mettere a punto questi parametri.
Anche se non l'ho visto enfatizzato nel link qui sotto, nota che alcuni garbage collector potrebbero non obbedire a questi parametri e di default java potrebbe sceglierne uno per te, se ti capita di avere più di un core (quindi l'argomento UseG1GC sopra ).
Aggiornamento: per Java 1.8.0_73 ho visto JVM rilasciare occasionalmente piccole quantità con le impostazioni predefinite. Sembra farlo solo se ~ 70% dell'heap è inutilizzato però .. non so se sarebbe più aggressivo rilasciando se il sistema operativo avesse poca memoria fisica.
Ho fatto esperimenti su questo.
È vero che System.gc();
suggerisce solo di eseguire Garbage Collector.
Ma chiamare System.gc();
dopo aver impostato tutti i riferimenti null
, migliorerà le prestazioni e l'occupazione della memoria.
Se vuoi veramente allocare e liberare un blocco di memoria puoi farlo con ByteBuffer diretti. C'è anche un modo non portatile per liberare la memoria.
Tuttavia, come è stato suggerito, solo perché devi liberare memoria in C, non significa che sia una buona idea farlo.
Se ritieni di avere davvero un buon caso d'uso gratuito (), ti preghiamo di includerlo nella domanda in modo che possiamo vedere cosa stai facendo, è molto probabile che ci sia un modo migliore.
Interamente da javacoffeebreak.com/faq/faq0012.html
Un thread a bassa priorità si occupa automaticamente della garbage collection per l'utente. Durante il tempo di inattività, il thread può essere richiamato e può iniziare a liberare memoria precedentemente allocata a un oggetto in Java. Ma non preoccuparti: non cancellerà i tuoi oggetti su di te!
Quando non ci sono riferimenti a un oggetto, questo diventa un gioco equo per il garbage collector. Invece di chiamare una routine (come gratuita in C ++), devi semplicemente assegnare tutti i riferimenti all'oggetto su null o assegnare una nuova classe al riferimento.
Esempio :
public static void main(String args[]) { // Instantiate a large memory using class MyLargeMemoryUsingClass myClass = new MyLargeMemoryUsingClass(8192); // Do some work for ( .............. ) { // Do some processing on myClass } // Clear reference to myClass myClass = null; // Continue processing, safe in the knowledge // that the garbage collector will reclaim myClass }
Se il codice sta per richiedere una grande quantità di memoria, è possibile richiedere al garbage collector di iniziare a recuperare spazio, anziché consentirgli di farlo come thread a bassa priorità. Per fare ciò, aggiungi quanto segue al tuo codice
System.gc();
Il garbage collector tenterà di recuperare spazio libero e l'applicazione potrà continuare a essere eseguita, con quanta più memoria possibile recuperata (su alcune piattaforme potrebbero applicarsi problemi di frammentazione della memoria).
Nel mio caso, poiché il mio codice Java dovrebbe essere trasferito in altre lingue nel prossimo futuro (principalmente C ++), almeno voglio pagare il servizio labiale per liberare memoria in modo adeguato, in modo da aiutare il processo di porting in seguito.
Personalmente mi affido alle variabili di annullamento come segnaposto per la corretta eliminazione futura. Ad esempio, mi prendo il tempo di annullare tutti gli elementi di un array prima di eliminare effettivamente (rendendo nullo) l'array stesso.
Ma il mio caso è molto particolare e so che sto facendo dei successi quando lo faccio.
* "Ad esempio, supponiamo che tu abbia dichiarato un Elenco all'inizio di un metodo che è cresciuto in dimensioni per essere molto grande, ma era richiesto solo fino a metà del metodo. A questo punto puoi impostare il riferimento Elenco su null per consentire al garbage collector di potenzialmente recuperare questo oggetto prima del completamento del metodo (e comunque il riferimento non rientra nell'ambito). " *
Questo è corretto, ma questa soluzione potrebbe non essere generalizzabile. Quando si imposta un riferimento all'oggetto Elenco su null -will- renderà disponibile la memoria per la garbage collection, questo vale solo per un oggetto Elenco di tipi primitivi. Se l'oggetto Elenco contiene invece tipi di riferimento, l'impostazione dell'oggetto Elenco = null non farà alcuna differenza tra i tipi di riferimento contenuti nell'elenco. In questo caso, l'impostazione di List object = null renderà orfani i tipi di riferimento contenuti i cui oggetti non saranno disponibili per la garbage collection a meno che l'algoritmo garbage collection non sia abbastanza intelligente da determinare che gli oggetti sono rimasti orfani.
Inoltre java fornisce la garbage collection automatica a volte vorrai sapere quanto è grande l'oggetto e quanto ne rimane. Memoria libera usando programmaticamente import java.lang;
e Runtime r=Runtime.getRuntime();
per ottenere valori di memoria usando mem1=r.freeMemory();
per liberare la memoria chiama il r.gc();
metodo e la chiamatafreeMemory()
La raccomandazione di JAVA è di assegnare a null
Da https://docs.oracle.com/cd/E19159-01/819-3681/abebi/index.html
L'assegnazione esplicita di un valore nullo a variabili non più necessarie consente al garbage collector di identificare le parti di memoria che possono essere recuperate in modo sicuro. Sebbene Java fornisca la gestione della memoria, non impedisce perdite di memoria o l'utilizzo di quantità eccessive di memoria.
Un'applicazione può indurre perdite di memoria non rilasciando riferimenti a oggetti. In questo modo si impedisce al garbage collector Java di recuperare quegli oggetti e si traduce in un aumento della quantità di memoria utilizzata. Annullare esplicitamente i riferimenti alle variabili dopo il loro utilizzo consente al garbage collector di recuperare la memoria.
Un modo per rilevare perdite di memoria è utilizzare strumenti di profilazione e acquisire istantanee di memoria dopo ogni transazione. Un'applicazione priva di perdite in stato stazionario mostrerà una memoria heap attiva costante dopo le garbage collection.