Dove sono memorizzati i campi primitivi?
I campi primitivi vengono archiviati come parte dell'oggetto che viene istanziato da qualche parte . Il modo più semplice di pensare a dove si trova è l'heap. Tuttavia , questo non è sempre il caso. Come descritto nella teoria e nella pratica di Java: Leggende delle prestazioni urbane, rivisitate :
Le JVM possono utilizzare una tecnica chiamata analisi di escape, in base alla quale possono dire che determinati oggetti rimangono confinati in un singolo thread per tutta la loro durata e che la durata è limitata dalla durata di un determinato stack frame. Tali oggetti possono essere allocati in modo sicuro nello stack anziché nell'heap. Ancora meglio, per piccoli oggetti, la JVM può ottimizzare completamente l'allocazione e semplicemente issare i campi dell'oggetto nei registri.
Pertanto, oltre a dire "l'oggetto è stato creato e anche il campo è presente", non si può dire se qualcosa è nell'heap o nello stack. Si noti che per oggetti piccoli e di breve durata, è possibile che l '"oggetto" non esista nella memoria in quanto tale e possa invece disporre i suoi campi direttamente nei registri.
Il documento si conclude con:
Le JVM sono sorprendentemente brave a capire cose che eravamo soliti presumere che solo lo sviluppatore potesse sapere. Consentendo alla JVM di scegliere tra allocazione di stack e allocazione di heap caso per caso, possiamo ottenere i vantaggi in termini di prestazioni dell'allocazione di stack senza far agonizzare il programmatore se allocare sullo stack o sull'heap.
Pertanto, se si dispone di un codice simile a:
void foo(int arg) {
Bar qux = new Bar(arg);
...
}
dove il ...
non consente qux
di lasciare quell'ambito, qux
può essere allocato nello stack. Questa è in realtà una vittoria per la VM perché significa che non deve mai essere spazzatura raccolta - scompare quando lascia l'ambito.
Altro su analisi di escape su Wikipedia. Per coloro che desiderano approfondire i lavori, Escape Analysis for Java di IBM. Per coloro che provengono da un mondo C #, potresti trovare le buone letture di Stack Is An Implementation e The Truth About Value di Eric Lippert (sono utili per i tipi Java anche perché molti dei concetti e degli aspetti sono uguali o simili) . Perché i libri .Net parlano dell'allocazione di memoria stack vs heap? anche in questo.
Sul perché della pila e del mucchio
Sul mucchio
Quindi, perché avere lo stack o l'heap? Per le cose che lasciano l'ambito, lo stack può essere costoso. Considera il codice:
void foo(String arg) {
bar(arg);
...
}
void bar(String arg) {
qux(arg);
...
}
void qux(String arg) {
...
}
Anche i parametri fanno parte dello stack. Nel caso in cui non si abbia un heap, si passerebbe l'intero set di valori nello stack. Questo va bene per "foo"
piccole stringhe ... ma cosa succederebbe se qualcuno inserisse un enorme file XML in quella stringa. Ogni chiamata sarebbe copiare l'intera stringa enorme nello stack - e che sarebbe del tutto uno spreco.
Invece, è meglio mettere gli oggetti che hanno una certa vita al di fuori dell'ambito immediato (passati a un altro ambito, bloccati in una struttura che qualcun altro sta mantenendo, ecc ...) in un'altra area che si chiama heap.
In pila
Non hai bisogno della pila. Si potrebbe ipoteticamente scrivere una lingua che non usa uno stack (di profondità arbitraria). Un vecchio BASIC che ho appreso in gioventù lo ha fatto, si potevano fare solo 8 livelli di gosub
chiamate e tutte le variabili erano globali - non c'era stack.
Il vantaggio dello stack è che quando si dispone di una variabile esistente con un ambito, quando si esce da tale ambito, il frame dello stack viene visualizzato. Semplifica davvero cosa c'è e cosa non c'è. Il programma passa a un'altra procedura, un nuovo frame dello stack; il programma ritorna alla procedura e sei tornato a quello che vede il tuo ambito attuale; il programma lascia la procedura e tutti gli oggetti nello stack vengono deallocati.
Questo semplifica davvero la vita alla persona che scrive il runtime per il codice di utilizzare uno stack e un heap. Sono semplicemente molti concetti e modi di lavorare sul codice che consente alla persona che scrive il codice nella lingua di essere liberata dal pensarlo esplicitamente.
La natura dello stack significa anche che non può essere frammentato. La frammentazione della memoria è un vero problema con l'heap. Allocare alcuni oggetti, quindi immondizia ne raccoglie uno centrale e quindi prova a trovare spazio per il prossimo grande da allocare. È un casino. Essere in grado di mettere le cose in pila significa invece che non devi occupartene.
Quando viene raccolta una spazzatura
Quando qualcosa viene raccolta, viene persa. Ma è solo spazzatura raccolta perché è già dimenticata: non ci sono più riferimenti all'oggetto nel programma a cui è possibile accedere dallo stato corrente del programma.
Sottolineerò che questa è una semplificazione molto grande della raccolta dei rifiuti. Esistono molti garbage collector (anche all'interno di Java - puoi modificare il garbage collector utilizzando vari flag ( documenti ). Questi si comportano in modo diverso e le sfumature di come ognuno fa le cose sono un po 'troppo profonde per questa risposta. Potresti voler leggere Nozioni di base di Java Garbage Collection per avere un'idea migliore di come funziona.
Detto questo, se qualcosa viene allocato nello stack, non viene immesso nella spazzatura come parte di System.gc()
- viene deallocato quando viene visualizzato il frame dello stack. Se qualcosa si trova nell'heap e fa riferimento a qualcosa nello stack, in quel momento non verrà raccolto.
Perché è importante?
Per la maggior parte, la sua tradizione. I libri di testo scritti e le classi del compilatore e la documentazione di vari bit fanno un grosso problema per l'heap e lo stack.
Tuttavia, le macchine virtuali di oggi (JVM e simili) hanno fatto di tutto per cercare di tenerlo nascosto al programmatore. A meno che tu non stia esaurendo l'uno o l'altro e abbia bisogno di sapere perché (piuttosto che aumentare semplicemente lo spazio di archiviazione in modo appropriato), non importa troppo.
L'oggetto si trova da qualche parte e si trova nel punto in cui è possibile accedervi correttamente e rapidamente per il periodo di tempo appropriato che esiste. Se è in pila o in pila, non importa davvero.