2016-02-13 9 views
15

Sono un newb, e ho letto su Garbage Collection dalle prime due risposte here.In che modo gli oggetti immutabili aiutano a ridurre il sovraccarico dovuto alla Garbage Collection?

Ora che giustifica l'uso di oggetti immutabili anche se il programmatore deve creare nuovi oggetti, rispetto all'utilizzo di oggetti esistenti (in applicazioni multi-threaded), this tutorial dice che il costo della creazione di oggetti è costituito dalla diminuzione overhead di memoria a causa di garbage collection, e l'eliminazione di codice per proteggere oggetti mutabili dai filetti di interferenza e consistenza memoria errori:

l'impatto della creazione scopo viene spesso sovrastimato, e può essere compensati da alcuni le efficienze associate agli oggetti immutabili. Questi includono overhead ridotto a causa della garbage collection e l'eliminazione del codice necessario per proteggere gli oggetti mutabili dalla corruzione .

La domanda è come? Che cosa ha a che fare la raccolta dei rifiuti con la mutabilità o l'immutabilità degli oggetti?

+3

Modern GC è estremamente efficiente con oggetti che "muoiono giovani". Non aver paura di creare e usare oggetti con breve durata; ma fai attenzione a mantenere gli oggetti di riferimento per un tempo più lungo (ad esempio per la memorizzazione nella cache). Il problema non è in realtà sull'immutabilità, più sulla durata della vita. – ZhongYu

+1

Nel tutorial che hai collegato, la frase esatta è _ "overhead decrescente a causa della garbage collection" _. Non c'è una parola "memoria" in essa. Dovresti correggerlo nella tua domanda, perché gli oggetti immutabili potrebbero effettivamente consumare più memoria (perché sei costretto a crearne uno nuovo se vuoi qualcosa cambiato in quello esistente), riducendo tuttavia l'onere complessivo su GC. Maggiori dettagli nella mia risposta qui sotto. –

risposta

11

A volte si assegna meno quando gli oggetti sono immutabili.

esempio semplice

Date getDate(){ 
    return copy(this.date); 
} 

devo copiare Date ogni volta che condivido perché è mutevole o il chiamante sarebbe in grado di mutare esso. Se getDate ottenere chiamato un sacco, il tasso di allocazione aumenterà drasticamente e questo avrebbe messo pressione sul GC

D'altra parte, sono Java-8 date immutabile

LocalDate getDate(){ 
    return this.date; 
} 

Si noti che non ho bisogno copiare la data (allocare un nuovo oggetto) a causa dell'immutabilità (sono felice di condividere l'oggetto con te perché so che non puoi mutarlo).

Ora si potrebbe pensare come posso applicare questo alle strutture di dati "utili" o complicate senza provocare allocazione massiccia (a causa di copie difensive), lei ha assolutamente ragione, ma c'è un'arte chiamata functional programming e persistent data structures (vale a dire: voi ottenere l'illusione che si tratta di una nuova copia in cui in effetti le copie condividono molto dall'originale).

Non bisogna meravigliarsi del fatto che la maggior parte dei linguaggi funzionali (tutti quelli di cui sono a conoscenza) sono spazzatura.

+0

Grazie mille.Mentre la risposta diversa dagli ultimi due paragrafi ha chiarito per me, non ho potuto dare molto senso agli ultimi due paragrafi. Puoi far luce se hai tempo, altrimenti va bene. Grazie ancora per la risposta. – Solace

+0

@Solace sei a conoscenza delle strutture dati funzionali? fanno un sacco di trucchi per evitare copie difensive "ingenue". –

+3

L'esempio @Solace One (molto semplice, classico) è un elenco: quando hai un elenco immutabile, ad es. una lista '[a, b, c, d, e]', quindi puoi implementare questa struttura dati (immutabile!) in un modo che ti permetta di "" rimuovere "" i primi due elementi da questa lista - ma questo ** non ** crea una nuova lista o modifica realmente quella esistente. Invece, otterrete il "sottolista" '[c, d, e]' che è supportato dalla stessa memoria del primo. Vedi anche https://en.wikipedia.org/wiki/Persistent_data_structure e relative domande StackOverflow. – Marco13

8

Gli oggetti non modificabili non necessitano di una copia difensiva se li si condivide in contesti (per esempio chiamando il codice di cui non ci si fida) o per la sicurezza del thread. Ciò può significare che le letture di oggetti immutabili possono essere inferiori in termini di spazzatura.

D'altra parte, ogni volta che si modifica un oggetto immutabile, è necessario creare nuovi oggetti, indipendentemente dal fatto che sia necessario o meno. A questo proposito, oggetti immutabili possono creare molta più spazzatura.

La vera domanda è se si stanno facendo molte letture, o molte scritture (o un mix) A seconda dell'utilizzo Gli oggetti immutabili possono salvare oggetti o creare più oggetti, quindi ha senso utilizzare oggetti immutabili o mutevoli basati sul tuo caso d'uso specifico.

Nota: la maggior parte delle volte, la correttezza è molto, molto più importante delle prestazioni, e mentre in generale gli oggetti immutabili hanno un IMHO superiore, è molto più facile dimostrare la correttezza dei modelli di dati utilizzando oggetti immutabili, ed è vale la pena usare oggetti immutabili per chiarezza e facilità di ragionamento da soli.

+2

Ho dovuto contrassegnare l'altra risposta come accettata a causa di quell'esempio, ma sono grato per il consiglio. È prezioso per me. Grazie mille davvero. – Solace

5

In this article Brian Goetz lo spiega bene. Fondamentalmente, è correlato al modo in cui funziona il garbage collector. Ha meno lavoro da fare se i nuovi oggetti fanno riferimento a quelli vecchi piuttosto che viceversa.

Estratto dall'articolo legato esempio classi indicati

public class MutableHolder { 
    private Object value; 
    public Object getValue() { return value; } 
    public void setValue(Object o) { value = o; } 
} 

public class ImmutableHolder { 
    private final Object value; 
    public ImmutableHolder(Object o) { value = o; } 
    public Object getValue() { return value; } 
} 

Nella maggior parte dei casi, quando un oggetto supporto viene aggiornato per fare riferimento a un oggetto diverso , il nuovo referente è un oggetto giovane. Se aggiorniamo uno MutableHolder chiamando setValue(), abbiamo creato una situazione dove un oggetto più vecchio fa riferimento a uno più giovane. D'altra parte, con creando un nuovo oggetto ImmutableHolder, un oggetto più giovane è che fa riferimento a uno più vecchio.

Quest'ultima situazione, in cui la maggior parte degli oggetti punta a oggetti più vecchi, è molto più delicata su un garbage collector generazionale. Se viene modificato un che vive nella vecchia generazione, tutti gli oggetti nella scheda che contengono lo MutableHolder devono essere scansionati per i riferimenti vecchio-giovani alla successiva raccolta secondaria.

L'uso di riferimenti mutabili per oggetti container a vita lunga aumenta il lavoro svolto per tracciare riferimenti vecchio-giovani alla data di raccolta .

analisi fuga

Per quanto riguarda la preoccupazione che un sacco di oggetti vengono creati perché si crea un'istanza di un nuovo oggetto ogni volta che è necessario modificare quello esistente, il meccanismo di allocazione degli oggetti è molto migliorata in tutte le JVM.

Dai uno sguardo allo escape analysis (citato anche nell'articolo collegato). Molti oggetti non saranno allocati sull'heap (ma saranno allineati/allocati sullo stack), quindi GC non avrà nulla a che fare con loro (in realtà GC non è a conoscenza dell'esistenza di tali oggetti).

Sebbene non correlato solo all'immutabilità, il meccanismo di analisi di escape può essere utilizzato in modo più efficiente in un contesto immutabile (un esempio è l'oggetto Person che non viene modificato durante l'invocazione del metodo nei documenti Oracle collegati).

+1

Sebbene non sia * strettamente * correlato all'immutabilità, la parola chiave ** "analisi di escape" ** vale davvero la pena indicare in questo contesto (avrei creato una propria risposta per questo, ma è anche spiegato nell'articolo che tu collegato a). +1 – Marco13