Où est le pool de constantes Java, le tas ou la stack?

Je connais le concept d’un pool de constantes et le pool de constantes Ssortingng utilisé par les JVM pour gérer les littéraux Ssortingng. Mais je ne sais pas quel type de mémoire est utilisé par la JVM pour stocker les littéraux constants Ssortingng. La stack ou le tas? Puisque c’est un littéral qui n’est associé à aucune instance, je suppose qu’il sera stocké dans la stack. Mais s’il n’est référé par aucune instance, le littéral doit être collecté par GC (corrigez-moi si je me trompe), alors comment cela est-il géré s’il est stocké dans la stack?

La réponse est techniquement non plus. Selon la spécification de machine virtuelle Java, la zone de stockage des littéraux de chaîne se trouve dans le pool constant d’exécution . La zone mémoire du pool constant à l’exécution est allouée par classe ou par interface, elle n’est donc liée à aucune instance d’object. Le pool de temps d’exécution est un sous-ensemble de la zone de méthode qui “stocke des structures par classe telles que le pool de constante d’exécution, les données de champ et de méthode et le code des méthodes et des constructeurs, y compris les méthodes spéciales utilisées pour l’initialisation et l’interface des classes et des instances. initialisation de type “. La spécification de la machine virtuelle indique que même si la zone de la méthode fait logiquement partie du tas, elle n’impose pas que la mémoire allouée dans la zone de la méthode soit soumise à un nettoyage de mémoire ou à d’autres comportements associés aux structures de données normales allouées au segment.

Comme expliqué dans cette réponse , l’emplacement exact du pool de chaînes n’est pas spécifié et peut varier d’une implémentation JVM à une autre.

Il est intéressant de noter que jusqu’à Java 7, le pool se trouvait dans l’espace permgen du tas sur la machine virtuelle Java à hotspot, mais il a été déplacé dans la partie principale du tas depuis Java 7 :

Zone : HotSpot
Synopsis : Dans JDK 7, les chaînes internes ne sont plus allouées dans la génération permanente du segment de mémoire Java, mais sont plutôt allouées dans la partie principale du segment de mémoire Java (appelées générations jeunes et anciennes), avec les autres objects créés par L’application. Cette modification se traduira par plus de données résidant dans le segment de mémoire principal Java et moins de données dans la génération permanente, ce qui peut nécessiter un ajustement de la taille des segments. La plupart des applications ne verront que des différences relativement faibles dans l’utilisation du tas en raison de ce changement, mais les applications plus volumineuses qui chargent de nombreuses classes ou qui utilisent beaucoup la méthode Ssortingng.intern () verront des différences plus significatives. RFE: 6962931

Et dans Java 8 Hotspot, la génération permanente a été complètement supprimée.

Les littéraux de chaîne ne sont pas stockés dans la stack.

Les littéraux de chaîne (ou plus précisément, les objects Ssortingng qui les représentent) ont été stockés historiquement dans un segment appelé tas “permgen”. (Permgen est l’abréviation de génération permanente.)

Dans des circonstances normales, les littéraux Ssortingng et la plupart des autres éléments du tas de permgen sont accessibles en permanence et ne sont pas récupérés. (Par exemple, les littéraux de chaîne sont toujours accessibles à partir des objects de code qui les utilisent.) Cependant, vous pouvez configurer une machine virtuelle Java pour tenter de rechercher et de collecter des classes chargées de manière inutile. .

CLARIFICATION # 1 – Je ne dis pas que Permgen n’est pas GC ‘. C’est le cas, généralement lorsque la JVM décide d’exécuter un GC complet. Ce que je veux dire, c’est que les littéraux Ssortingng seront accessibles tant que le code qui les utilise est accessible et que le code sera accessible tant que le chargeur de classes du code sera accessible et pour les chargeurs de classes par défaut.

CLARIFICATION # 2 – En fait, Java 7 stocke les objects Ssortingng internes dans le tas normal. Cela inclut (je présume) un object Ssortingng qui représente des littéraux de chaîne. (Voir la réponse de @ assylias pour plus de détails.)

Pool de chaînes

Le regroupement de chaînes (parfois aussi appelé canonisation de chaînes) est un processus consistant à remplacer plusieurs objects Ssortingng de valeur égale mais ayant une identité différente par un seul object Ssortingng partagé. Vous pouvez atteindre cet objective en conservant votre propre carte (avec des références faibles ou faibles selon vos besoins) et en utilisant les valeurs de carte comme valeurs canoniques. Ou vous pouvez utiliser la méthode Ssortingng.intern () qui vous est fournie par JDK.

À certains moments de Java 6, l’utilisation de Ssortingng.intern () était interdite par de nombreuses normes en raison de la possibilité élevée d’obtenir une exception OutOfMemoryException si le regroupement était hors de contrôle. L’implémentation Oracle Java 7 du pool de chaînes a été considérablement modifiée. Vous pouvez rechercher des détails dans http://bugs.sun.com/view_bug.do?bug_id=6962931 et http://bugs.sun.com/view_bug.do?bug_id=6962930 .

Ssortingng.intern () dans Java 6

Au bon vieux temps, toutes les chaînes internes étaient stockées dans PermGen – la partie de taille fixe du tas principalement utilisée pour stocker les classes chargées et le pool de chaînes. Outre les chaînes explicitement intégrées, le pool de chaînes PermGen contenait également toutes les chaînes littérales utilisées précédemment dans votre programme (le mot important est utilisé ici – si une classe ou une méthode n’a jamais été chargée / appelée, toutes les constantes définies ne seront pas chargées).

Le plus gros problème avec un tel pool de chaînes dans Java 6 était son emplacement – le PermGen. PermGen a une taille fixe et ne peut pas être étendu à l’exécution. Vous pouvez le définir en utilisant l’option -XX: MaxPermSize = 96m. Pour autant que je sache, la taille par défaut du PermGen varie entre 32M et 96M selon la plate-forme. Vous pouvez augmenter sa taille, mais sa taille sera toujours corrigée. Une telle limitation nécessitait une utilisation très attentive de Ssortingng.intern – vous feriez mieux de ne pas utiliser d’intrants utilisateurs non contrôlés en utilisant cette méthode. C’est pourquoi la mise en pool de chaînes à certains moments de Java 6 a été principalement implémentée dans les cartes gérées manuellement.

Ssortingng.intern () dans Java 7

Les ingénieurs Oracle ont apporté un changement extrêmement important à la logique de regroupement de chaînes dans Java 7: le pool de chaînes a été déplacé vers le tas. Cela signifie que vous n’êtes plus limité par une zone de mémoire de taille fixe distincte. Toutes les chaînes se trouvent désormais dans le tas, comme la plupart des objects ordinaires, ce qui vous permet de gérer uniquement la taille du tas lors du réglage de votre application. Techniquement, cela seul pourrait être une raison suffisante pour reconsidérer l’utilisation de Ssortingng.intern () dans vos programmes Java 7. Mais il y a d’autres raisons.

Les valeurs de pool de chaînes sont récupérées

Oui, toutes les chaînes du pool de chaînes JVM sont éligibles à la récupération de place s’il n’y a aucune référence à celles-ci depuis les racines de votre programme. Cela s’applique à toutes les versions discutées de Java. Cela signifie que si votre chaîne internée est hors de scope et qu’il n’y a aucune autre référence à celle-ci – ce sera la corbeille collectée dans le pool de chaînes JVM.

Etant éligible pour le nettoyage de la mémoire et résidant dans le tas, un pool de chaînes JVM semble être le bon endroit pour toutes vos chaînes, n’est-ce pas? En théorie, c’est vrai – les chaînes non utilisées seront récupérées dans le pool, les chaînes utilisées vous permettront d’économiser de la mémoire si vous obtenez une chaîne égale à l’entrée. Semble être une stratégie d’économie de mémoire parfaite? Presque. Vous devez savoir comment le pool de chaînes est implémenté avant de prendre des décisions.

la source.

Aux grandes réponses qui ont déjà été incluses ici, je veux append quelque chose qui manque dans ma perspective – et illustration.

Comme vous l’avez déjà fait, JVM divise la mémoire allouée en un programme Java en deux parties. l’un est stack et l’autre est tas . Stack est utilisé à des fins d’exécution et heap est utilisé à des fins de stockage. Dans cette mémoire de tas, JVM alloue de la mémoire spécialement conçue pour les littéraux de chaîne. Cette partie de la mémoire de tas est appelée pool de constantes de chaîne .

Par exemple, si vous lancez les objects suivants:

Ssortingng s1 = "abc"; Ssortingng s2 = "123"; Ssortingng obj1 = new Ssortingng("abc"); Ssortingng obj2 = new Ssortingng("def"); Ssortingng obj3 = new Ssortingng("456); 

Les littéraux de chaîne s1 et s2 iront dans le pool de constantes de chaîne, les objects obj1, obj2, obj3 au tas. Tous seront référencés à partir de la stack.

Notez également que “abc” apparaîtra dans le tas et dans le pool de chaînes constantes. Pourquoi Ssortingng s1 = "abc" et Ssortingng obj1 = new Ssortingng("abc") seront créés de cette façon? C’est parce que Ssortingng obj1 = new Ssortingng("abc") crée explicitement une instance nouvelle et référentielle distincte d’un object Ssortingng s1 = "abc" et Ssortingng s1 = "abc" peut réutiliser une instance du pool de chaînes constantes s’il en existe un. Pour une explication plus élaborée: https://stackoverflow.com/a/3298542/2811258

entrer la description de l'image ici

Comme d’autres réponses l’expliquent, la mémoire en Java est divisée en deux parties

1. Pile: une stack est créée par thread et stocke les images de stack qui stockent à nouveau les variables locales. Si une variable est un type de référence, cette variable fait référence à un emplacement de mémoire en tas pour l’object réel.

2. Heap: Tous les types d’objects seront créés uniquement en tas.

La mémoire de tas est à nouveau divisée en 3 parties

1. Young Generation: Stocke des objects qui ont une courte vie, Young Generation elle-même peut être divisé en deux catégories: Eden Space et Survivor Space .

2. Ancienne génération: stocke les objects qui ont survécu à de nombreux cycles de nettoyage de la mémoire et sont toujours référencés.

3. Génération permanente: Stocke les métadonnées relatives au programme, par exemple le pool constant à l’exécution.

Le pool de constantes de chaînes appartient à la zone de génération permanente de la mémoire Heap.

Comme indiqué dans la section Comment la JVM gère-t-elle la surcharge et le remplacement des méthodes en interne , nous pouvons voir le pool de constante d’exécution de notre code dans le bytecode à l’aide de javap -verbose class_name qui affichera les références de méthode (#Methodref) littéraux de chaîne (#Ssortingng)

pool-temps d'exécution