allocation statique en java - tas, pile et génération permanente

117

Dernièrement, j'ai beaucoup lu sur les schémas d'allocation de mémoire en java, et il y a eu beaucoup de doutes car j'ai lu à partir de diverses sources. J'ai rassemblé mes concepts et je demanderais à passer en revue tous les points et à les commenter. J'ai appris que l'allocation de mémoire est spécifique à la JVM, donc je dois dire à l'avance que ma question est spécifique à Sun.

  1. Les classes (chargées par les chargeurs de classes) vont dans une zone spéciale sur le tas: Génération permanente
  2. Toutes les informations relatives à une classe comme le nom de la classe, les tableaux d'objets associés à la classe, les objets internes utilisés par JVM (comme java / lang / Object) et les informations d'optimisation vont dans la zone de génération permanente.
  3. Toutes les variables membres statiques sont à nouveau conservées dans la zone de génération permanente.
  4. Les objets vont sur un tas différent: Jeune génération
  5. Il n'y a qu'une seule copie de chaque méthode par classe, qu'elle soit statique ou non statique. Cette copie est placée dans la zone de génération permanente. Pour les méthodes non statiques, tous les paramètres et variables locales vont sur la pile - et chaque fois qu'il y a une invocation concrète de cette méthode, nous obtenons un nouveau cadre de pile qui lui est associé. Je ne sais pas où sont stockées les variables locales d'une méthode statique. Sont-ils sur le tas de la génération permanente? Ou simplement leur référence est stockée dans la zone de génération permanente, et la copie réelle est ailleurs (où?)
  6. Je ne sais pas non plus où le type de retour d'une méthode est stocké.
  7. Si les objets (dans la jeune génération) doivent utiliser un membre statique (dans la génération permanente), ils reçoivent une référence au membre statique && ils disposent de suffisamment d'espace mémoire pour stocker le type de retour de la méthode, etc.

Merci d'avoir traversé ça!

Jaguar
la source

Réponses:

152

Premièrement, comme il devrait être clair pour vous maintenant, il y a très peu de personnes qui peuvent confirmer ces réponses à partir de connaissances de première main. Très peu de personnes ont travaillé sur les JVM HotSpot récentes ou les ont étudiées de manière approfondie pour vraiment les connaître. La plupart des gens ici (moi y compris) répondent en fonction de ce qu'ils ont vu écrit ailleurs ou de ce qu'ils ont déduit. Habituellement, ce qui est écrit ici, ou dans divers articles et pages Web, est basé sur d'autres sources qui peuvent ou non être définitives. Souvent, il est simplifié, inexact ou tout simplement faux.

Si vous voulez une confirmation définitive de vos réponses, vous devez vraiment télécharger le code source OpenJDK ... et faire vos propres recherches en lisant et en comprenant le code source. Poser des questions sur le SO ou parcourir des articles Web aléatoires n'est pas une bonne technique de recherche universitaire.

Ayant dit cela ...

... ma question est spécifique à Sun.

Au moment où cette question a été posée, Sun Microsystems avait cessé d'exister. La question était donc spécifique à Oracle. AFAIK, toutes les implémentations JVM tierces actuelles (sans recherche) sont soit des ports directs d'une version d'OpenJDK, soit descendant d'une autre version de Sun / Oracle.

Les réponses ci-dessous s'appliquent aux versions d'Oracle Hotspot et d'OpenJDK, et probablement à la plupart des autres également ... y compris GraalVM.

1) Les classes (chargées par les chargeurs de classes) vont dans une zone spéciale sur le tas: Génération permanente.

Avant Java 8, oui.

À partir de Java 8, l'espace PermGen a été remplacé par Metaspace. Les classes chargées et compilées en JIT y vont maintenant. PermGen n'existe plus.

2) Toutes les informations relatives à une classe comme le nom de la classe, les tableaux d'objets associés à la classe, les objets internes utilisés par JVM (comme java / lang / Object) et les informations d'optimisation vont dans la zone de génération permanente.

Plus ou moins, oui. Je ne sais pas ce que vous entendez par certaines de ces choses. Je suppose que "les objets internes utilisés par JVM (comme java / lang / Object)" signifie des descripteurs de classe internes à JVM.

3) Toutes les variables membres statiques sont à nouveau conservées dans la zone de génération permanente.

Les variables elles-mêmes oui. Ces variables (comme toutes les variables Java) contiendront des valeurs primitives ou des références d'objet. Cependant, alors que les variables membres statiques sont dans une trame allouée dans le tas permgen, les objets / tableaux auxquels ces variables font référence peuvent être alloués dans n'importe quel tas.

4) Les objets vont sur un tas différent: jeune génération

Pas nécessairement. Les objets volumineux peuvent être attribués directement à la génération titulaire.

5) Il n'y a qu'une seule copie de chaque méthode par classe, qu'elle soit statique ou non statique. Cette copie est placée dans la zone de génération permanente.

En supposant que vous faites référence au code de la méthode, alors AFAIK oui. Cela peut cependant être un peu plus compliqué. Par exemple, ce code peut exister sous forme de bytecode et / ou de code natif à différents moments de la vie de la JVM.

... Pour les méthodes non statiques, tous les paramètres et variables locales vont sur la pile - et chaque fois qu'il y a une invocation concrète de cette méthode, nous obtenons un nouveau stack-frame qui lui est associé.

Oui.

... Je ne sais pas où sont stockées les variables locales d'une méthode statique. Sont-ils sur le tas de la génération permanente? Ou simplement leur référence est stockée dans la zone de génération permanente, et la copie réelle est ailleurs (où?)

Non. Elles sont stockées sur la pile, tout comme les variables locales dans les méthodes non statiques.

6) Je ne sais pas non plus où le type de retour d'une méthode est stocké.

Si vous voulez dire la valeur retournée par un appel de méthode (non-void), alors elle est renvoyée sur la pile ou dans un registre machine. S'il est retourné sur la pile, cela prend 1 ou deux mots, selon le type de retour.

7) Si les objets (dans la jeune génération) doivent utiliser un membre statique (dans la génération permanente), ils reçoivent une référence au membre statique && ils disposent de suffisamment d'espace mémoire pour stocker le type de retour de la méthode, etc. .

C'est inexact (ou du moins, vous ne vous exprimez pas clairement).

Si une méthode accède à une variable membre statique, elle obtient une valeur primitive ou une référence d' objet . Cela peut être assigné à une variable ou un paramètre local (existant), assigné à un membre statique ou non statique (existant), assigné à un élément (existant) d'un tableau précédemment alloué, ou simplement utilisé et rejeté.

  • En aucun cas, une nouvelle mémoire n'a besoin d'être allouée pour contenir une référence ou une valeur primitive.

  • En général, un mot de mémoire suffit pour stocker une référence d'objet ou de tableau, et une valeur primitive occupe généralement un ou deux mots, selon l'architecture matérielle.

  • En aucun cas, il n'est nécessaire d'allouer de l'espace par l'appelant pour contenir un objet / tableau retourné par une méthode. En Java, les objets et les tableaux sont toujours renvoyés à l'aide de la sémantique passe par valeur ... mais la valeur renvoyée est une référence d'objet ou de tableau.


Pour plus d'informations, veuillez consulter ces ressources:

Stephen C
la source