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:
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:
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?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 ).Java.lang.String
classe, si oui, pourquoi?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.
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:
Permettez-moi de commencer par mettre ces 2 diagrammes décrivant les zones de mémoire JVM:
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 ).
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.
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.
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.
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ë.
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.
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).
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 ).
É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").