Java stack e gestione della memoria heap


Voglio sapere come viene allocata la memoria nel seguente programma:

public class MemoryClass {

    public static void main(final String[] args) {
        int i = 0;
        MemoryClass memoryClass = new MemoryClass();
        memoryClass.myMethod(memoryClass);
    }

    private void myMethod(final Object obj) {
        int i = 1;
        String s = "HelloWorld!";

    }

}

Ora, per quanto riguarda la mia comprensione, il seguente diagramma descrive come avviene l'allocazione della memoria:
Base runtime allocazione della memoria


Nel diagramma sopra, memoria,obj e s, che sono nella memoria dello stack, sono in realtà i riferimenti ai loro " oggetti reali" che sono posizionati all'interno della memoria dell'heap.
Ecco la serie di domande che mi vengono in mente:

  1. Dove sono memorizzati i metodi di s?
  2. Se avessi creato un altro oggetto di MemoryClass all'interno di myMethod, JVM allocherebbe nuovamente la memoria per gli stessi metodi all'interno della memoria dello stack?
  3. JVM libererebbe la memoria allocata a myMethodnon appena la sua esecuzione è completata, in tal caso, come gestirebbe la situazione menzionata nella domanda 2 ( applicabile solo se JVM alloca la memoria più volte allo stesso metodo ).
  4. Cosa sarebbe stato il caso, se avessi dichiarato solo s e non l'avessi inizializzato, JVM avrebbe ancora allocato memoria a tutti i metodi della classe java.lang.String, in caso affermativo,perché?
Author: Adit A. Pillai, 2016-12-13

3 answers

Dove sono memorizzati i metodi di s?

Sono memorizzati nell'oggetto String class; è un oggetto caricato da un oggetto ClassLoader quando String viene fatto riferimento per la prima volta nel programma. Tutte le implementazioni della JVM che esistevano quando ho letto di quest'ultima non hanno mai deallocato la memoria per un oggetto di classe una volta caricato. E ' sul mucchio.

Se avessi creato un altro oggetto di MemoryClass all'interno di myMethod, JVM avrebbe allocato memoria per gli stessi metodi di nuovo all'interno della memoria dello stack?

No, i metodi e i dati per gli oggetti vengono mantenuti separatamente, in particolare perché la JVM non ha mai bisogno di più di una copia dei metodi.

JVM libererebbe la memoria allocata a myMethod non appena la sua esecuzione è completata, in tal caso, come gestirebbe la situazione menzionata nella domanda 2(applicabile solo se JVM alloca la memoria più volte allo stesso metodo).

N. Java generalmente non "immediatamente libera la memoria" di cose memorizzate nell'heap. Farebbe girare le cose troppo lentamente. Libera la memoria solo quando viene eseguito il garbage collector, e lo fa solo quando il suo algoritmo per l'esecuzione del garbage collector decide che è il momento.

Quale sarebbe stato il caso, se avessi dichiarato solo s e non l'avessi inizializzato, JVM avrebbe ancora allocato memoria a tutti i metodi di java.lang.Classe String, se è così, perché?

Questo dipende dall'implementazione della JVM, penso, e forse dal compilatore. Se si dichiara una variabile e non la si usa mai, è del tutto possibile (e comune) che il compilatore noti che non è utile e non lo inserisca nel file di classe. Se non è nel file di classe, non viene mai referenziato, e quindi esso ei suoi metodi non vengono caricati, ecc. Se il compilatore lo inserisce comunque ma non viene mai referenziato, allora il ClassLoader non avrebbe alcun motivo per caricarlo, ma sono un po ' vago sul fatto che venga caricato o meno. Potrebbe dipendere dalla JVM implementazione; carica le cose perché ci sono variabili della classe o solo quando vengono referenziate? Quanti algoritmi ClassLoader possono ballare sulla testa di un PIN a 4 cifre?

Ti incoraggio a leggere su JVM e classloader e simili; otterrai molto di più leggendo una spiegazione di come funziona piuttosto che frugare con esempi che puoi inventare.

 14
Author: arcy, 2016-12-13 12:27:42

Prima le cose importanti: Presumo che le tue domande stiano venendo fuori dopo aver letto questo articolo (perché laggiù vedo un diagramma molto simile al tuo ) quindi non citerò o evidenzierò nessuno dei punti che sono menzionati laggiù e cercherò di rispondere alle tue domande con punti che non erano così evidenti in quel post.

Leggendo a tutte le tue domande, la mia impressione è che tu sia chiaro su come la memoria è allocata in stack e heap ma hanno dubbi sui metadati delle classi, cioè dove nella memoria, i metodi delle classi sarebbero stati memorizzati e come sarebbero stati riciclati. Quindi, prima fammi provare a spiegare le aree di memoria JVM:


Aree di memoria JVM

Vorrei iniziare mettendo questi 2 diagrammi raffiguranti aree di memoria JVM:

Fonte del diagramma

inserisci qui la descrizione dell'immagine

Fonte del diagramma

inserisci qui la descrizione dell'immagine

Ora, come chiaro dal sopra i diagrammi di seguito è riportata la struttura ad albero della memoria JVM e cercherò di gettare luce sullo stesso (@Adit: si prega di notare che l'area che ti riguarda è lo spazio PermGen o lo spazio di generazione permanente di memoria non-heap).

  • Memoria heap
    • Giovani generazioni
      • Spazio Eden
      • Spazio sopravvissuto
    • Vecchia generazione
      • Generazione di ruolo
  • NONCAP memoria
    • Generazione permanente
    • Cache di codice (Penso incluso "solo" da HotSpot Java VM)

Memoria heap

La memoria heap è l'area dati di runtime da cui la VM Java alloca la memoria per tutte le istanze e gli array di classe. L'heap può essere di dimensioni fisse o variabili. Il garbage collector è un sistema di gestione automatica della memoria che recupera la memoria heap per gli oggetti.

Giovani generazioni

Giovane la generazione è il luogo in cui vengono creati tutti i nuovi oggetti. Quando la giovane generazione è piena, viene eseguita la garbage collection. Questa garbage collection è chiamata Minor GC. Giovane generazione è divisa in sotto 2 parti

Eden space: Il pool da cui viene inizialmente allocata la memoria per la maggior parte degli oggetti.

Survivor space: La piscina contenente oggetti sopravvissuti alla garbage collection dello spazio Eden.

Vecchia generazione

Vecchio La memoria di generazione contiene gli oggetti che sono vissuti a lungo e sopravvissuti dopo molti giri di GC minori. Di solito la garbage collection viene eseguita nella memoria di vecchia generazione quando è piena. La raccolta dei rifiuti di vecchia generazione è chiamata Major GC e di solito richiede più tempo. Vecchia generazione contiene sotto parte:

Spazio di ruolo: Il pool contenente oggetti che esistono da qualche tempo nello spazio sopravvissuto.

Memoria non-Heap

La memoria non-heap include un area del metodo condivisa tra tutti i thread e la memoria necessaria per l'elaborazione interna o l'ottimizzazione per la VM Java. Memorizza strutture per classe come un pool di costanti di runtime, dati di campo e metodo e il codice per metodi e costruttori. L'area del metodo è logicamente parte dell'heap ma, a seconda dell'implementazione, una VM Java potrebbe non raccoglierla o compattarla. Come la memoria heap, l'area del metodo può essere di dimensioni fisse o variabili. La memoria per l'area del metodo non deve essere contiguo.

Generazione permanente

Il pool contenente tutti i dati riflettenti della macchina virtuale stessa, ad esempio oggetti di classe e metodo. Con le macchine virtuali Java che utilizzano la condivisione dei dati di classe, questa generazione è divisa in aree di sola lettura e lettura-scrittura.

Cache di codice

La VM Java HotSpot include anche una cache di codice, contenente memoria che viene utilizzata per la compilazione e l'archiviazione del codice nativo.


Rispondere alle domande dell'OP in particolare

Dove sono memorizzati i metodi di s?

Memoria non-Heap > > Generazione permanente

Se avessi creato un altro oggetto di MemoryClass all'interno di myMethod, sarebbe JVM allocare nuovamente la memoria per gli stessi metodi all'interno della memoria dello stack?

La memoria stack contiene solo variabili locali in modo che la tua ORV (object reference variable) di new MemoryClass venga comunque creata nel frame stack di myMethod, ma JVM non caricherà tutti i metodi, metadati ecc. di MemoryClass di nuovo in "Generazione permanente".

JVM carica la classe solo una volta e quando carica la classe, lo spazio viene allocato su "Generazione permanente" per quella classe e ciò accade solo una volta mentre la classe viene caricata da JVM.

JVM libererebbe la memoria allocata a myMethod non appena è l'esecuzione è completata, in tal caso, come gestirebbe la situazione menzionato nella domanda 2(applicabile solo se JVM alloca memoria più volte allo stesso metodo).

Il frame di stack creato per myMethod verrà rimosso dalla memoria dello stack, quindi tutta la memoria creata per le variabili locali verrà pulita ma ciò non significa che JVM ripulirà la memoria allocata in "Generazione permanente" per la classe quegli oggetti che hai creato in myMethod

Quale sarebbe stato il caso, se avessi solo dichiarato s e non l'avessi fatto inizializzarlo, JVM allocherebbe ancora memoria a tutti i metodi di Java.lang.Classe String, se è così, Perché?

In particolare parlando della classe String, JVM avrebbe allocato spazio per String in "Generazione permanente" troppo presto, mentre JVM viene avviato e se inizializzi la variabile String o meno, non importa dal punto di vista della "Generazione permanente".

Parlando di altre classi definite dall'utente, JVM caricherà la classe e allocherà la memoria in "Generazione permanente" non appena si definisce la classe, anche se non si crea un oggetto della classe, la memoria viene allocata in " Generazione permanente "(area non-heap ) e quando si crea un oggetto della classe, la memoria viene allocata in" Eden Space " (area heap ).


Fonti di informazioni di cui sopra e ulteriori lettura:

 6
Author: hagrawal, 2017-05-23 12:18:35

Poiché la risposta accettata di arsy e la risposta di hagrawal sono chiare, voglio solo approfondire la quarta domanda:

Quale sarebbe stato il caso, se avessi dichiarato solo s e non l'avessi fatto inizializzarlo, JVM allocherebbe ancora memoria a tutti i metodi di Java.lang.Classe String, se è così, perché?

Fondamentalmente è vero che i dati della classe-che hanno le informazioni sui campi e sui metodi-sono memorizzati nella generazione permanente (meta-spazio da JDK-8 in poi), è importante notare che sono gli oggetti all'interno di java.lang.Classe String (come il char [] che contiene tutte le informazioni sui caratteri per quella stringa) per cui i dati sono allocati nell'heap.

Ciò non avviene fino a quando non viene creato un nuovo oggetto string, utilizzando la parola chiave 'new' o creando una nuova stringa letterale (ad esempio: "helloworld").

 2
Author: Ravindra HV, 2016-12-29 19:43:16