L’utilizzo di finale per le variabili in Java migliorare la raccolta dei rifiuti)?

Oggi i miei colleghi e me hanno una discussione circa l’utilizzo del final parola chiave in Java per migliorare la raccolta dei rifiuti.

Per esempio, se si scrive un metodo come:

public Double doCalc(final Double value)
{
   final Double maxWeight = 1000.0;
   final Double totalWeight = maxWeight * value;
   return totalWeight;  
}

Dichiarare le variabili nel metodo final di aiutare la garbage collection per ripulire la memoria da variabili inutilizzate nel metodo, dopo che il metodo uscite.

È vero questo?



14 Replies
  1. 81

    Qui è un po ‘ diverso esempio, con riferimento finale-campi di tipo piuttosto che il valore finale-tipo di variabili locali:

    public class MyClass {
    
       public final MyOtherObject obj;
    
    }

    Ogni volta che si crea un’istanza della Classe, sarete in grado di creare un’uscita di riferimento per un MyOtherObject istanza, e il GC dovrà seguire il link per cercare gli oggetti live.

    La JVM utilizza un mark-sweep GC algoritmo, che deve esaminare tutti i live refereces in GC “root” posizioni (come tutti gli oggetti nella corrente dello stack di chiamata). Ogni oggetto è “segnato” come essere vivo, e qualsiasi oggetto a cui si riferisce un oggetto è segnato anche come essere vivo.

    Dopo il completamento della fase di segno di spunta, il GC spazia attraverso l’heap, di liberare memoria per tutti smarcato oggetti (e la compattazione della memoria per le restanti oggetti dal vivo).

    Inoltre, è importante riconoscere che il Java heap della memoria è partizionata in un “giovani generazioni” e di “vecchia generazione”. Tutti gli oggetti sono stati allocati nei giovani (a volte indicato come “vivaio”). Dal momento che la maggior parte degli oggetti sono di breve durata, il GC è più aggressivo su come liberare recenti spazzatura per le giovani generazioni. Se un oggetto sopravvive un ciclo di raccolta delle giovani generazioni, viene spostato nella vecchia generazione (a volte indicato come il “professore di ruolo di generazione”), che viene elaborato, meno frequentemente.

    Così, al largo della parte superiore della mia testa, ho intenzione di dire “no, il “finale” del modificatore non aiuta il GC ridurre il carico di lavoro”.

    A mio parere, la migliore strategia per ottimizzare la propria gestione della memoria in Java è quello di eliminare le spurie riferimenti il più rapidamente possibile. Si può fare anche tramite l’assegnazione di “null” per un riferimento a un oggetto non appena hai finito di usarlo.

    O, meglio ancora, ridurre le dimensioni di ogni dichiarazione di ambito. Per esempio, se si dichiara un oggetto all’inizio di un 1000-line metodo, e se l’oggetto rimane viva fino alla fine di quel metodo di ambito (l’ultima parentesi graffa di chiusura), l’oggetto potrebbe rimanere in vita per molto più tempo che in realtà necessario.

    Se si utilizzano metodi di piccole dimensioni, con solo una decina di righe di codice, quindi gli oggetti dichiarati all’interno di tale metodo di cadere al di fuori del campo di applicazione più rapidamente, e il GC sarà in grado di fare la maggior parte del suo lavoro all’interno del molto più efficiente e per le giovani generazioni. Non si desidera che gli oggetti spostati nella generazione precedente, a meno che non assolutamente necessario.

    • Cibo per la mente. Ho sempre pensato che il codice in linea è stato più veloce, ma se la jvm esegue a corto di memoria, allora sarà lento come bene. hmmmmm…
    • Sono solo supposizioni… ma presumo che il compilatore JIT può inline finale valori primitivi (e non oggetti), per il modesto aumento delle prestazioni. Codice inline, invece, è in grado di produrre significative ottimizzazioni, ma non ha nulla a che fare con la finale di variabili.
    • Non sarebbe possibile assegnare il valore null per un oggetto finale, poi, forse, finale invece di aiutare, potrebbe rendere le cose più difficili
    • Si potrebbe utilizzare { } per limitare l’ambito in un grande metodo, piuttosto che di rottura a diversi metodi privati che potrebbero non essere pertinenti per altri metodi della classe.
    • È inoltre possibile utilizzare le variabili locali al posto dei campi, quando è possibile, al fine di migliorare la memoria, raccolta dei rifiuti e per ridurre referenziale legami.
  2. 37

    Dichiarazione di una variabile locale final non influenzerà la raccolta dei rifiuti, non solo significa che non è possibile modificare la variabile. Il tuo esempio sopra non dovrebbero compilare, come si sta modificando la variabile totalWeight che è stata contrassegnata final. D’altra parte, la dichiarazione di un primitivo (double invece di Double) final permette che la variabile sia inlined nel codice chiamante, in modo che possano causare un po ‘ di memoria e di miglioramento delle performance. Questo viene utilizzato quando si dispone di un numero di public static final Strings in una classe.

    In generale, il compilatore di runtime e di ottimizzare i dove possono. È meglio scrivere il codice in modo appropriato e non cercare di essere troppo difficile. Utilizzare final quando non si desidera che la variabile da modificare. Si supponga che ogni facile ottimizzazioni sarà eseguita dal compilatore, e se siete preoccupati per la prestazione o l’utilizzo di memoria, utilizzare un profiler per determinare il vero problema.

  3. 25

    No, non è affatto vero.

    Ricordare che final non significa costante, significa che non è possibile modificare il riferimento.

    final MyObject o = new MyObject();
    o.setValue("foo"); //Works just fine
    o = new MyObject(); //Doesn't work.

    Ci può essere qualche piccola ottimizzazione del tutto la consapevolezza che la JVM non avrà mai a modificare il riferimento (come ad esempio controllare per vedere se è cambiato), ma sarebbe così piccolo da non preoccuparsi.

    Final dovrebbe essere pensato come utile meta-dati per lo sviluppatore e non come un compilatore di ottimizzazione.

  4. 15

    Alcuni punti da chiarire:

    • Annulla riferimento non deve aiutare GC. Se lo facesse, non potrebbe indicare che le variabili sono più di ambito. Unica eccezione è il caso di oggetto nepotismo.

    • C’è nessuna allocazione dello stack di sicurezza in Java.

    • Dichiarazione di una variabile finale significa che non è possibile (in condizioni normali) assegnare un nuovo valore alla variabile. Dal finale non dice nulla circa il campo di applicazione, non dice nulla circa l’efficacia di GC.

    • L’allocazione dello stack (di primitive e i riferimenti agli oggetti nell’heap) in java: stackoverflow.com/a/8061692/32453 Java richiede gli stessi oggetti di chiusura come una classe anonima/lambda per essere in finale, ma scopre che è solo per ridurre i requisiti di memoria, telaio”/ridurre la confusione per cui è correlato il suo essere raccolti…
  5. 11

    Beh, io non so l’uso del “finale” modificatore in questo caso, o il suo effetto sul GC.

    Ma io può dirvi questo: l’utilizzo del Boxed valori piuttosto primitive (ad esempio, il Doppio, invece di doppio) allocazione di tali oggetti nel mucchio, piuttosto che la pila, e si occuperà di produrre inutili rifiuti che il GC sarà necessario pulire.

    Io uso solo boxed primitive quando richiesto da un API esistenti, o quando ho bisogno di nullable primitive.

    • Hai ragione. Ho solo bisogno di un rapido esempio per spiegare la mia domanda.
  6. 5

    Finale variabili non può essere modificato dopo l’assegnazione iniziale (imposto dal compilatore).

    Questo non cambia il comportamento del garbage collection come tale. Unica cosa è che queste variabili non può essere annullato quando non viene utilizzato più (il che potrebbe aiutare il processo di garbage collection in memoria di situazioni stretti).

    Si deve sapere che il finale consente al compilatore di fare ipotesi su ciò che per ottimizzare. Inline codice e non compreso il codice non raggiungibile.

    final boolean debug = false;
    
    ......
    
    if (debug) {
      System.out.println("DEBUG INFO!");
    }

    Al println non sarà incluso nel byte di codice.

  7. 3

    GC agisce sul irraggiungibile rif. Questo non ha nulla a che fare con il “finale”, che è semplicemente un’affermazione di assegnazione. È possibile che alcuni VM GC può fare uso di “finale”? Io non so come o perché.

  8. 3

    Non c’è un modo ben noto caso d’angolo con generazionale garbage collector. (Per una breve descrizione di leggere la risposta da benjismith per un approfondimento leggere gli articoli alla fine).

    L’idea in generazionale GCs è che la maggior parte del tempo solo giovani generazioni hanno bisogno di essere considerati. Il percorso principale è scansionato, e poi la giovane generazione di oggetti di scansione. Durante questo più frequenti spazza nessun oggetto di vecchia generazione, controllato.

    Ora, il problema deriva dal fatto che un oggetto non è consentito avere i riferimenti per i piccoli oggetti. Quando una longeva (vecchia generazione) oggetto ottiene un riferimento a un nuovo oggetto, che il riferimento deve essere esplicitamente monitorati dal garbage collector (vedi articolo da IBM sul hotspot JVM collezionista), realtà che interessano il GC performance.

    Il motivo per cui un oggetto vecchio non può riferirsi ad uno più giovane che, come il vecchio oggetto di controllo non è selezionata in collezioni minori, se il solo riferimento all’oggetto è conservato nel vecchio oggetto, non marcato, e sarebbe erroneamente deallocato durante la scansione di fase.

    Ovviamente, come detto da molti, la parola chiave final non reallly influenzare il garbage collector, ma garantisce che il riferimento non potrà mai essere cambiato in un più giovane oggetto se questo oggetto sopravvive alle collezioni e la rende al vecchio heap.

    Articoli:

    IBM sulla raccolta dei rifiuti: storia, in hotspot JVM e prestazioni. Questi potrebbero non essere più pienamente valida, in quanto risale nel 2003/04, ma si danno alcune di facile lettura, la visione di GCs.

    Sole Ottimizzazione di garbage collection

  9. 3

    final su variabili locali e parametri non fa alcuna differenza per il file di classe di prodotto, in modo da non influire sulle prestazioni di runtime. Se una classe non ha sottoclassi, HotSpot considera che classe, come se fosse in finale (o comunque è possibile annullare in seguito, se una classe che rompe l’ipotesi è caricato). Credo final sui metodi più o meno lo stesso come classi. final sul campo statico può consentire che la variabile deve essere interpretata come una “compilazione” costante di tempo e ottimizzazione essere fatto da javac su quella base. final su campi consente la JVM di una certa libertà di ignorare accade-prima relazioni.

  10. 2

    Sembra che ci sia un sacco di risposte che sono senza congetture. La verità è che non c’è nessun modificatore finale per le variabili locali a livello di bytecode. La macchina virtuale non potrà mai sapere che le variabili locali sono stati definiti come finale o meno.

    La risposta alla tua domanda è un no categorico.

    • Questo potrebbe essere vero, ma il compilatore può ancora utilizzare le informazioni finali durante il flusso di dati di analisi.
    • il compilatore già sa che una variabile è impostata solo una volta. Ha a che fare analisi del flusso di dati già in ordine, sapere che una variabile può essere null, non è inizializzato prima dell’uso, etc. Così, locali finali non offrono tutte le informazioni per il compilatore.
    • Non è così. Flusso dei dati di analisi in grado di dedurre un sacco di cose, ma è possibile avere un turing programma completo all’interno di un blocco che sarà o non sarà impostare una variabile locale. Il compilatore non può sapere in anticipo se la variabile sarà scritto e sarà costante a tutti. Pertanto il compilatore, senza la parola chiave final, non può garantire che una variabile è definitiva o meno.
    • Sono veramente incuriosito, puoi fare un esempio? Non vedo come ci possa essere un finale di assegnazione per un non-finale variabile che il compilatore non sa nulla. Il compilatore sa che se si dispone di una variabile non inizializzata, ti aiuta a non usarlo. Se si tenta di assegnare una variabile finale all’interno di un ciclo, il compilatore non ti. Che cosa è un esempio in cui una variabile che PUÒ essere dichiarato come finale, ma NON lo è, e il compilatore non può garantire che esso è definitiva? Ho il sospetto che qualsiasi esempio potrebbe essere una variabile che non può essere dichiarato come finale, in primo luogo.
    • Ah dopo la ri-leggendo il tuo commento, vedo che il tuo esempio è una variabile inizializzata all’interno di un blocco condizionale. Tali variabili non può essere definitiva, in primo luogo, salvo che la condizione di percorsi di inizializzare la variabile tempo. Così, il compilatore non sai su tali dichiarazioni – che consente di compilare un finale variabile inizializzata in due luoghi diversi (si pensi final int x; if (cond) x=1; else x=2;). Il compilatore, senza la parola chiave final, quindi in grado di garantire che una variabile è definitiva o meno.
    • Quello che ho cercato di dire è che, senza un finale, il compilatore non sa che una variabile è in realtà una costante (anche se potrebbe essere una costante). Con la finale, è sicuro. Il che significa che la finale permette per ulteriori ottimizzazioni che senza di loro.
    • Hmm, dovrete dare un esempio. Io ancora sono sicuro che il compilatore sa che con o senza la parola chiave se una variabile è costante. Immaginate questo: il compilatore “finge” che ogni variabile locale viene dichiarata finale. Se è in grado di compilare con la variabile finale, ora “sa” che può essere in finale senza la parola chiave. Se riesco a compilare, è al contrario “sa” che la variabile non può essere definitiva. O se non chi è aggiunta la parola chiave nel testo non ha alcuna influenza su questo.
    • Un caso in cui una variabile è costante, ma il compilatore non è in grado di rilevare. int a=1; while(a<100) a*=2; [in questa posizione ‘a’ è sempre 128]. Comunque capisco il tuo problema qui perché questo codice non può essere scritto con la finale. Un interessante esempio potrebbe essere un caso in cui si potrebbe aggiungere finale e dove sarebbe effettivamente aiutare il compilatore.
    • Il “turing completo’ esempio: { int a = 3; if (complexFalse()) a = 4; } dove complexFalse() è un metodo che il compilatore non è in grado di dimostrare sarà sempre falso (cfr. l’arresto-problema). In questo caso non si poteva dichiarare un finale senza conversione if-statement in un ternario espressione—al punto che il flusso di dati funziona di nuovo comunque. IOW, mentre, ovviamente, corretta, l’eccezione non è utile nella pratica.
    • Che esempio non è valido, però; a nel tuo esempio non può essere dichiarato come finale. {final int a = 3; if (complexFalse()) a = 4} non compilare in Java, in modo che la presenza o l’assenza di final parola chiave non si applica. Il punto è che non c’è mai nulla di un essere umano può fare con il modificatore final (in Java), che indicano il compilatore nulla che già non sappiamo.

  11. 1

    Tutti il metodo e la variabile può essere sottoposto a override bydefault in sottoclassi.Se vogliamo salvare il sottoclassi overridig i membri della superclasse,possiamo dichiarare come finale utilizzando la parola chiave finale.
    E.g-
    final int a=10;
    final void display(){......}
    Facendo un metodo finale garantisce che la funzionalità definito nella superclasse non potrà mai essere cambiato comunque. Allo stesso modo il valore di una variabile finale non può mai essere cambiato. Finale variabili si comporta come variabili di classe.

  12. 0

    L’unica cosa che posso pensare è che il compilatore potrebbe ottimizzare il via la finale variabili e inline loro come costanti nel codice, così si finisce con la memoria non allocata.

  13. 0

    assolutamente, come lungo come rendere oggetto la vita più breve che porta un grande beneficio di gestione della memoria, di recente, abbiamo esaminato la funzionalità di esportazione di avere variabili di istanza su una prova e un’altra prova di avere a livello di metodo variabile locale. durante il test di carico, JVM getta outofmemoryerror sulla prima prova e con la JVM ha fermato. ma nella seconda prova, con successo, in grado di ottenere il report, grazie a una migliore gestione della memoria.

  14. 0

    L’unica volta che io preferisco dichiarare le variabili locali come finale quando:

    • Ho hanno per farli finale in modo che possano essere condivisi con classe anonima (per esempio: la creazione di daemon thread e permetterà l’accesso un po ‘ di valore da racchiude metodo)

    • Ho desidera per farli finale (per esempio: un valore che non dovrebbe/non avere sovrascritto per errore)

    Non sono di aiuto in rapida raccolta dei rifiuti)?

    AFAIK un oggetto diventa un candidato di GC collection se ha zero riferimenti forti e in quel caso non vi è alcuna garanzia che essi saranno immediatamente la procedura di garbage collection . In generale, un riferimento forte è detto a morire quando si va al di fuori del campo di applicazione o utente in modo esplicito riassegnare a null punto di riferimento, quindi, dichiarando il loro finale di riferimento continuerà ad esistere fino a che il metodo esiste (a meno che il suo campo di applicazione è esplicitamente limitati a specifici interno del blocco {}) perché non è possibile riassegnare finale variabili. Quindi penso che w.r.t Garbage Collection “finale” può introdurre un indesiderato possibile ritardo.

Lascia un commento