allocazione statica in java: heap, stack e generazione permanente


117

Ultimamente ho letto molto sugli schemi di allocazione della memoria in java e ci sono stati molti dubbi mentre leggevo da varie fonti. Ho raccolto i miei concetti e vorrei chiedere di esaminare tutti i punti e commentarli. Sono venuto a sapere che l'allocazione della memoria è specifica per JVM, quindi devo dire in anticipo che la mia domanda è specifica per Sun.

  1. Le classi (caricate dai classloader) vanno in un'area speciale sull'heap: Permanent Generation
  2. Tutte le informazioni relative a una classe come il nome della classe, gli array di oggetti associati alla classe, gli oggetti interni utilizzati da JVM (come java / lang / Object) e le informazioni di ottimizzazione vanno nell'area di generazione permanente.
  3. Tutte le variabili membro statiche vengono nuovamente mantenute nell'area Generazione permanente.
  4. Gli oggetti vanno su un mucchio diverso: giovani generazioni
  5. C'è solo una copia di ogni metodo per classe, sia il metodo statico che non statico. Quella copia viene inserita nell'area Generazione permanente. Per i metodi non statici, tutti i parametri e le variabili locali vanno nello stack - e ogni volta che c'è una chiamata concreta di quel metodo, otteniamo un nuovo stack-frame ad esso associato. Non sono sicuro di dove siano memorizzate le variabili locali di un metodo statico. Sono sul mucchio di Permanent Generation? O solo il loro riferimento è memorizzato nell'area Generazione permanente e la copia effettiva è da qualche altra parte (dove?)
  6. Inoltre, non sono sicuro di dove viene memorizzato il tipo restituito di un metodo.
  7. Se gli oggetti (nella giovane generazione) devono utilizzare un membro statico (nella generazione permanente), viene fornito loro un riferimento al membro statico && hanno spazio di memoria sufficiente per memorizzare il tipo di ritorno del metodo, ecc.

Grazie per averlo affrontato!

Risposte:


152

Innanzitutto, come dovrebbe esserti ormai chiaro che sono pochissime le persone che possono confermare queste risposte dalla conoscenza di prima mano. Pochissime persone hanno lavorato alle recenti JVM HotSpot o le hanno studiate fino alla profondità necessaria per conoscerle veramente. La maggior parte delle persone qui (me compreso) rispondono in base a cose che hanno visto scritte altrove o a ciò che hanno dedotto. Di solito ciò che è scritto qui, o in vari articoli e pagine web, si basa su altre fonti che possono o meno essere definitive. Spesso è semplificato, impreciso o semplicemente sbagliato.

Se vuoi una conferma definitiva delle tue risposte, devi davvero scaricare il codice sorgente OpenJDK ... e fare le tue ricerche leggendo e comprendendo il codice sorgente. Fare domande su SO, o sfogliare articoli web casuali non è una solida tecnica di ricerca accademica.

Avendolo detto ...

... la mia domanda è specifica per il sole.

Quando è stata posta questa domanda, Sun Microsystems aveva cessato di esistere. La domanda era quindi specifica per Oracle. Per quanto ne so, tutte le attuali implementazioni JVM di terze parti (non di ricerca) sono porte dirette di una versione OpenJDK o discendono da un'altra versione Sun / Oracle.

Le risposte seguenti si applicano alle versioni Oracle Hotspot e OpenJDK e probabilmente anche alla maggior parte degli altri ... incluso GraalVM.

1) Le classi (caricate dai classloader) vanno in un'area speciale sull'heap: Permanent Generation.

Prima di Java 8, sì.

A partire da Java 8, lo spazio PermGen è stato sostituito con Metaspace. Le classi caricate e compilate con JIT ora vanno lì. PermGen non esiste più.

2) Tutte le informazioni relative a una classe come il nome della classe, gli array di oggetti associati alla classe, gli oggetti interni utilizzati da JVM (come java / lang / Object) e le informazioni di ottimizzazione vanno nell'area di generazione permanente.

Più o meno sì. Non sono sicuro di cosa intendi con alcune di queste cose. Immagino che "oggetti interni usati da JVM (come java / lang / Object)" significhi descrittori di classe interni a JVM.

3) Tutte le variabili membro statiche vengono nuovamente mantenute nell'area Generazione permanente.

Le variabili stesse sì. Queste variabili (come tutte le variabili Java) conterranno valori primitivi o riferimenti a oggetti. Tuttavia, mentre le variabili membro statiche si trovano in un frame allocato nell'heap permgen, gli oggetti / array a cui fanno riferimento tali variabili possono essere allocati in qualsiasi heap.

4) Gli oggetti vanno su un mucchio diverso: giovani generazioni

Non necessariamente. Oggetti di grandi dimensioni possono essere allocati direttamente nella generazione di ruolo.

5) C'è solo una copia di ogni metodo per classe, sia il metodo statico che non statico. Quella copia viene inserita nell'area Generazione permanente.

Supponendo che ti riferisci al codice del metodo, allora per quanto ne so. Potrebbe essere un po 'più complicato però. Ad esempio, quel codice può esistere in bytecode e / o in formati di codice nativo in momenti diversi durante la vita della JVM.

... Per i metodi non statici, tutti i parametri e le variabili locali vanno nello stack - e ogni volta che c'è una chiamata concreta di quel metodo, otteniamo un nuovo stack-frame ad esso associato.

Sì.

... Non sono sicuro di dove siano memorizzate le variabili locali di un metodo statico. Sono sul mucchio di Permanent Generation? O solo il loro riferimento è memorizzato nell'area Generazione permanente e la copia effettiva è da qualche altra parte (dove?)

No. Sono memorizzate nello stack, proprio come le variabili locali nei metodi non statici.

6) Non sono nemmeno sicuro di dove viene memorizzato il tipo di ritorno di un metodo.

Se intendi il valore restituito da una chiamata al metodo (non void), viene restituito nello stack o in un registro della macchina. Se viene restituito in pila, questo richiede 1 o due parole, a seconda del tipo di ritorno.

7) Se gli oggetti (nella giovane generazione) devono usare un membro statico (nella generazione permanente), viene dato loro un riferimento al membro statico && hanno abbastanza spazio di memoria per memorizzare il tipo di ritorno del metodo, ecc. .

Questo è inesatto (o almeno, non ti stai esprimendo chiaramente).

Se un metodo accede a una variabile membro statica, ciò che ottiene è un valore primitivo o un riferimento a un oggetto . Questo può essere assegnato a una variabile locale (esistente) o a un parametro, assegnato a un membro statico o non statico (esistente), assegnato a un elemento (esistente) di una matrice allocata in precedenza o semplicemente utilizzato e scartato.

  • In nessun caso è necessario allocare una nuova memoria per contenere un riferimento o un valore primitivo.

  • In genere, una parola di memoria è tutto ciò che è necessario per memorizzare un riferimento a un oggetto o a un array e un valore primitivo occupa tipicamente una o due parole, a seconda dell'architettura hardware.

  • In nessun caso il chiamante deve allocare spazio per contenere un oggetto / array restituito da un metodo. In Java, gli oggetti e gli array vengono sempre restituiti utilizzando la semantica del valore di passaggio ... ma il valore restituito è un riferimento a un oggetto o ad un array.


Per ulteriori informazioni, fare riferimento a queste risorse:

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.