web-dev-qa-db-fra.com

Java gestion de la pile 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!";

    }

}

Maintenant, autant que je sache, le diagramme suivant décrit comment l'allocation de mémoire a lieu:
Basic runtime memory allocation


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

  1. Où sont stockées les méthodes de s ?
  2. Si j'avais créé un autre objet de MemoryClass à l'intérieur myMethod, la JVM allouerait-elle à nouveau de la mémoire pour les mêmes méthodes dans la mémoire de la pile?
  3. La JVM libérerait-elle la mémoire allouée à myMethod dès la fin de son exécution, si oui, comment gérerait-elle la situation mentionnée à la question 2 ( applicable uniquement si JVM alloue plusieurs fois de la mémoire à la même ).
  4. Ce qui 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 Java.lang.String classe, si oui, pourquoi?
19
Adit A. Pillai

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

Ils sont stockés dans l'objet de classe String; 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 sur ce dernier 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 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?

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.

Est-ce que JVM libérerait 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 libre" des choses stockées sur le tas. Cela ralentirait les choses. Il ne libère de la mémoire que lorsque le garbage collector s'exécute, et il le fait seulement lorsque son algorithme pour exécuter le garbage collector décide qu'il est temps.

Qu'est-ce qui aurait été le cas, si je n'avais déclaré que s et 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?

Cela dépend de l'implémentation 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) que le compilateur remarque qu'il ne sert à rien et ne la place pas 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 place de toute façon mais qu'il n'est jamais référencé, alors le ClassLoader n'aurait aucune raison de chargez-le, mais je suis un peu vague sur le fait qu'il soit chargé ou non. Peut dépendre de la mise en œuvre de la JVM; cela 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 tellement plus en lisant une explication de la façon dont cela fonctionne plutôt qu'en la fouillant avec des exemples que vous pouvez imaginer.

19
arcy

Tout d'abord: Je suppose que vos questions sortent après avoir lu this article ( parce que là-bas je vois un diagramme très similaire au vôtre) donc je ne citerai ni ne soulignerai aucun des points qui sont mentionnés là-bas et j'essaierai de répondre à vos questions avec des points qui ont été pas si évident dans ce post.

En lisant toutes vos questions, j'ai l'impression que vous êtes clair sur la façon dont la mémoire est allouée en pile et en tas, mais avez 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, permettez-moi d'abord d'essayer d'expliquer les zones de mémoire JVM:


Zones de mémoire JVM

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

Source du diagramme

enter image description here

Source du diagramme

enter image description here

Maintenant, comme le montrent les diagrammes ci-dessous, la structure arborescente de la mémoire JVM et j'essaierai de l'éclairer ( @ Adit: veuillez noter que la zone qui vous concerne est PermGen Space ou espace de génération permanent de mémoire non-tas ).

  • Mémoire de tas
    • Jeune génération
      • Eden Space
      • Espace Survivant
    • Ancienne génération
      • Génération permanente
  • Mémoire non-tas
    • Génération permanente
    • Cache de code ( je pense inclus "uniquement" 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 le Java VM 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 de mémoire automatique qui récupère la mémoire de tas pour les objets.

Jeune génération

La jeune génération est le lieu où tous les nouveaux objets sont créés. Lorsque la jeune génération est remplie, la collecte des ordures est effectuée. Ce garbage collection s'appelle Minor GC. Young Generation est divisé en moins de 2 parties

Espace Eden: Le pool à partir duquel la mémoire est initialement allouée à 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

La mémoire de l'ancienne génération contient les objets qui ont vécu longtemps et survécu après de nombreuses séries de GC mineurs. Habituellement, le ramassage des ordures est effectué dans la mémoire de l'ancienne génération lorsqu'elle est pleine. La collecte des déchets de l'ancienne génération est appelée GC majeur 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 segmentée comprend une zone de méthode partagée entre tous les threads et la mémoire requise pour le traitement interne ou l'optimisation pour la machine virtuelle Java. Elle stocke les structures par classe telles qu'un pool constant de champs d'exécution, un champ et les données de méthode et le code des méthodes et des constructeurs. La zone de méthode fait logiquement partie du tas mais, selon l'implémentation, un Java VM peut ne pas garbage collect ou compact. Comme la mémoire de tas, la zone de méthode peut être de taille fixe ou variable. La mémoire de la zone de méthode n'a pas besoin d'être contiguë.

Génération permanente

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 Java VM 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

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


Répondre spécifiquement aux questions de l'OP

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

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

Si j'avais créé un autre objet 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?

La mémoire de la pile ne contient que des variables locales, de sorte que votre ORV (variable de référence d'objet) du nouveau MemoryClass serait toujours créé dans le cadre de la pile de myMethod, mais la JVM ne chargerait pas toutes les méthodes, métadonnées, etc. de MemoryClass à nouveau dans "Génération permanente".

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

Est-ce que JVM libérerait 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).

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

Qu'est-ce qui aurait été le cas, si je n'avais déclaré que s et 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?

En ce qui concerne spécifiquement la classe String, JVM aurait alloué trop tôt de l'espace pour String en "génération permanente", tandis que JVM est lancée et que vous initialisiez ou non votre variable String, elle ne le fait pas. matière du point de vue de la "génération permanente".

En parlant d'autres classes définies par l'utilisateur, la JVM chargerait la classe et allouerait de la mémoire dans "Génération permanente" dès que vous définiriez 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" ( zone non tas ) et lorsque vous créez un objet de la classe, la mémoire est allouée dans "Eden Space" ( zone de tas ).


Sources des informations ci-dessus et lectures complémentaires:

7
hagrawal

Étant donné que la réponse acceptée par l'arsy et la réponse de Hagrawal sont claires, je veux juste développer la quatrième question:

Qu'est-ce qui aurait été le cas, si je n'avais déclaré que s et 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?

Fondamentalement, alors qu'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 Java.lang. Classe de chaîne (telle que char [] qui contient toutes les informations de caractère pour cette chaîne) pour laquelle des données sont allouées sur le tas.

Cela ne se produit qu'après la création d'un nouvel objet chaîne - soit en utilisant le mot clé 'new', soit en créant un nouveau littéral chaîne (par exemple: "helloworld").

2
Ravindra HV