Gestion de la pile Java et de la mémoire de tas


Je veux savoir comment la mémoire est allouée dans le programme suivant:

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!";

    }

}

, selon ma compréhension, le schéma suivant décrit la façon dont l'allocation de mémoire a lieu:
Allocation de mémoire d'exécution de base


Dans le diagramme ci-dessus, mémoire,obj et s, qui sont dans la pile de la mémoire, sont en fait les références à leur "objets réels" qui sont placés à l'intérieur de la mémoire de masse.
Voici l'ensemble des questions qui viennent à mon esprit:

  1. Où sont les méthodes de s stockées?
  2. Si j'avais créé un autre objet de MemoryClass dans myMethod, la JVM allouerait-elle à nouveau de la mémoire pour les mêmes méthodes dans la mémoire de la pile?
  3. JVM libérerait-elle la mémoire allouée à myMethoddès que son exécution est terminée, si oui, comment gérerait-elle la situation mentionnée à la question 2( applicable uniquement si JVM alloue de la mémoire plusieurs fois à la même méthode).
  4. Quoi cela aurait été le cas, si j'avais seulement déclaré s et que je ne l'avais pas initialisé, la JVM allouerait-elle toujours de la mémoire à toutes les méthodes de la classe java.lang.String, si oui,pourquoi?
Author: Adit A. Pillai, 2016-12-13

3 answers

Où sont stockées les méthodes de s?

Ils sont stockés dans l'objet String class; c'est un objet chargé par un objet ClassLoader lorsque String est référencé pour la première fois dans le programme. Toutes les implémentations de la JVM qui existaient lorsque j'ai lu à ce sujet n'ont jamais désalloué la mémoire pour un objet de classe une fois qu'il a été chargé. C'est sur le tas.

Si j'avais créé un autre objet de MemoryClass dans myMethod, JVM allouerait-il de la mémoire pour les mêmes méthodes encore une fois dans la mémoire de la pile?

Non, les méthodes et les données des objets sont conservées séparément, notamment parce que la JVM n'a jamais besoin de plus d'une copie des méthodes.

JVM libérerait-elle la mémoire allouée à myMethod dès que son exécution est terminée, si oui, comment gérerait-elle la situation mentionnée à la question 2(applicable uniquement si JVM alloue de la mémoire plusieurs fois à la même méthode).

Non. Java ne "libère généralement pas immédiatement la mémoire" de les choses stockées sur le tas. Cela rendrait les choses tournent trop lentement. Il ne libère de la mémoire que lorsque le garbage collector s'exécute, et il ne le fait que lorsque son algorithme d'exécution du garbage collector décide qu'il est temps.

Quel aurait été le cas, si je n'avais déclaré que s et ne l'avais pas initialisé, JVM allouerait-elle toujours de la mémoire à toutes les méthodes de java.lang.Classe String,si oui,pourquoi?

Cela dépend de l'implémentation de la JVM, je pense, et peut-être du compilateur. Si vous déclarez une variable et ne l'utilisez jamais, il est tout à fait possible (et courant) pour le compilateur de remarquer qu'il n'y a aucune utilité pour elle et de ne pas la mettre dans le fichier de classe. S'il n'est pas dans le fichier de classe, il n'est jamais référencé, et donc lui et ses méthodes ne sont pas chargés, etc. Si le compilateur le met de toute façon mais qu'il n'est jamais référencé, alors le ClassLoader n'aurait aucune raison de le charger, mais je suis un peu vague sur le fait qu'il soit chargé ou non. Peut dépendre de la JVM implémentation; charge-t-il des choses parce qu'il y a des variables de la classe ou seulement quand elles sont référencées? Combien d'algorithmes ClassLoader peuvent danser sur la tête d'un code PIN à 4 chiffres?

Je vous encourage à lire sur la JVM et les ClassLoaders et autres; vous gagnerez beaucoup plus en lisant une explication de son fonctionnement plutôt que de la fouiller avec des exemples que vous pouvez imaginer.

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

Tout d'abord: Je suppose que vos questions sortent après avoir lu cet article ( parce que là-bas je vois un diagramme très similaire à la vôtre) donc je ne citerai ni ne mettrai en évidence aucun des points mentionnés là-bas et essaierai de répondre à vos questions avec des points qui n'étaient pas si évidents dans ce post.

En lisant toutes vos questions, mon impression est que vous êtes clair sur la façon dont la mémoire est allouée dans la pile et tas mais ont des doutes sur les métadonnées des classes, c'est-à-dire où dans la mémoire, les méthodes des classes seraient stockées et comment elles seraient recyclées. Alors, laissez-moi d'abord essayer d'expliquer les zones de mémoire JVM:


Zones de mémoire JVM

Permettez-moi de commencer par mettre ces 2 diagrammes représentant les zones de mémoire JVM:

Source de diagramme

entrez la description de l'image ici

Source de diagramme

entrez la description de l'image ici

Maintenant, comme il ressort clairement de la les diagrammes ci-dessus ci-dessous sont la structure arborescente de la mémoire JVM et je vais essayer de faire la lumière sur la même chose (@Adit: veuillez noter que la zone qui vous concerne est l'espace PermGen ou l'espace de génération permanent de mémoire non-tas).

  • Mémoire de tas
    • Jeune génération
      • Espace Eden
      • Espace survivant
    • Ancienne génération
      • Génération permanente
  • NonHeap mémoire
    • Génération Permanente
    • Cache de code (Je pense inclus "seulement" par HotSpot Java VM)

Mémoire de tas

La mémoire de tas est la zone de données d'exécution à partir de laquelle la machine virtuelle Java alloue de la mémoire pour toutes les instances de classe et les tableaux. Le tas peut être de taille fixe ou variable. Le garbage collector est un système de gestion automatique de la mémoire qui récupère la mémoire de tas pour les objets.

Jeune génération

Jeune la génération est l'endroit où tous les nouveaux objets sont créés. Lorsque la jeune génération est remplie, la collecte des ordures est effectuée. Cette garbage collection est appelée Minor GC. La jeune génération est divisée en 2 parties ci-dessous

Eden space: Le pool à partir duquel la mémoire est initialement allouée pour la plupart des objets.

Espace survivant: Le pool contenant des objets qui ont survécu à la collecte des ordures de l'espace Eden.

Ancienne génération

Ancien La mémoire de génération contient les objets qui ont une longue durée de vie et ont survécu après de nombreux tours de GC mineur. Habituellement, la récupération de place est effectuée dans la mémoire de l'ancienne génération lorsqu'elle est pleine. La collecte des ordures de l'ancienne génération est appelée Major GC et prend généralement plus de temps. L'ancienne génération contient la partie ci-dessous:

Espace permanent: Le pool contenant des objets qui existent depuis un certain temps dans l'espace survivant.

Mémoire non-tas

La mémoire non-tas comprend un zone de méthode partagée entre tous les threads et la mémoire requise pour le traitement interne ou l'optimisation de la machine virtuelle Java. Il stocke des structures par classe telles qu'un pool de constantes d'exécution, des données de champ et de méthode, ainsi que le code des méthodes et des constructeurs. La zone de méthode fait logiquement partie du tas mais, selon l'implémentation, une machine virtuelle Java peut ne pas la collecter ou la compacter. Comme la mémoire de tas, la zone de la méthode peut être de taille fixe ou variable. La mémoire de la zone de méthode ne besoin d'être contiguës.

Génération Permanente

Le pool contenant toutes les données réfléchissantes de la machine virtuelle elle-même, telles que les objets de classe et de méthode. Avec les machines virtuelles Java qui utilisent le partage de données de classe, cette génération est divisée en zones en lecture seule et en lecture-écriture.

Cache de code

La machine virtuelle Java HotSpot comprend également un cache de code, contenant de la mémoire utilisée pour la compilation et le stockage du code natif.


Répondre aux questions de l'OP plus précisément

Où sont stockées les méthodes de s?

Mémoire non-Tas > > Génération permanente

Si j'avais créé un autre objet de MemoryClass dans myMethod, JVM allouer de la mémoire pour les mêmes méthodes à nouveau dans la mémoire de la pile?

La mémoire de pile ne contient que des variables locales, donc votre ORV (object reference variable) de new MemoryClass serait toujours créé dans le cadre de pile de myMethod, mais JVM ne chargerait pas toutes les méthodes, les métadonnées etc. de MemoryClass à nouveau dans "Génération permanente".

La JVM ne charge la classe qu'une seule fois et lorsqu'elle charge la classe, l'espace est alloué sur la "Génération permanente" pour cette classe et cela ne se produit qu'une seule fois pendant que la classe est chargée par la JVM.

JVM libérerait-elle la mémoire allouée à myMethod dès qu'elle est l'exécution est terminée, si oui, comment gérerait-il la situation mentionné à la question 2 (applicable uniquement si la JVM alloue de la mémoire plusieurs fois dans la même méthode).

Le cadre de pile créé pour myMethod sera supprimé de la mémoire de la pile, donc toute la mémoire créée pour les variables locales sera nettoyée mais cela ne signifie pas que JVM nettoiera la mémoire allouée dans "Génération permanente" pour la classe les objets que vous avez créés dans myMethod

Quel aurait été le cas, si j'avais seulement déclaré s et ne l'ai pas fait initialisez-le, la JVM allouerait-elle toujours de la mémoire à toutes les méthodes de Java.lang.Classe String, si oui, Pourquoi?

En parlant spécifiquement de la classe String, la JVM aurait alloué de l'espace pour String dans la "Génération permanente" beaucoup trop tôt, pendant que la JVM est lancée et que vous initialisiez votre variable de chaîne ou non, cela n'a pas d'importance du point de vue de la "Génération permanente".

En parlant d'autres classes définies par l'utilisateur, JVM chargerait la classe et allouerait de la mémoire en "Génération permanente" dès que vous définissez la classe, encore une fois même si vous ne créez pas d'objet de la classe, la mémoire est allouée dans "Génération Permanente" (non-tas zone) et lorsque vous créez un objet de la classe alors que la mémoire est allouée dans "l'Eden de l'Espace" (tas de domaine).


Sources des informations ci-dessus et autres lecture:

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

Puisque la réponse acceptée de l'arsy et la réponse de hagrawal sont claires, je veux juste élaborer sur la quatrième question:

Quel aurait été le cas, si j'avais seulement déclaré s et ne l'ai pas fait initialisez-le, la JVM allouerait-elle toujours de la mémoire à toutes les méthodes de Java.lang.Classe String,si oui,pourquoi?

Fondamentalement, il est vrai que les données de classe-qui contiennent les informations sur les champs et les méthodes-sont stockées dans la génération permanente (méta-espace à partir de JDK-8), il est important de noter que ce sont les objets dans le java.lang.Classe String (telle que char [] qui contient toutes les informations de caractères de cette chaîne) pour laquelle des données sont allouées sur le tas.

Cela ne se produit pas tant qu'un nouvel objet string n'est pas créé - soit en utilisant le mot-clé 'new', soit en créant un nouveau littéral string (par exemple: "helloworld").

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