111 votes

Où se trouve le pool de constantes String de Java, dans le tas ou dans la pile ?

Je connais le concept de pool de constantes et le pool de constantes String utilisé par les JVM pour gérer les littéraux String. Mais je ne sais pas quel type de mémoire est utilisé par la JVM pour stocker les littéraux des constantes String. La pile ou le tas ? Comme il s'agit d'une constante littérale qui n'est associée à aucune instance, je suppose qu'elle sera stockée dans la pile. Mais s'il n'est référencé par aucune instance, le littéral doit être collecté par l'exécution de la GC (corrigez-moi si je me trompe), alors comment cela est-il géré s'il est stocké dans la pile ?

13 votes

Comment un pool peut-il être stocké sur la pile ? Connaissez-vous le concept de pile ?

1 votes

Salut Scrum Meister, j'ai essayé de dire que ce n'est pas possible. Désolé pour la mauvaise convention. En ce qui concerne GC, c'est maintenant que je le sais. Merci pour cela

0 votes

@TheScrumMeister - en fait, dans certaines circonstances, ils peut être Les déchets sont collectés. Le problème est que l'objet de code de toute classe qui mentionne un littéral de chaîne de caractères aura une référence à l'objet String qui représente le littéral.

79voto

Duane Moore Points 236

La réponse est techniquement ni l'un ni l'autre. Selon les spécifications de la machine virtuelle de Java, la zone de stockage des chaînes de caractères se trouve dans le répertoire de la machine virtuelle. pool de constantes d'exécution . La zone mémoire du pool de constantes d'exécution est allouée par classe ou par interface, elle n'est donc pas liée à des instances d'objets. Le pool de constantes d'exécution est un sous-ensemble de la zone de mémoire de l'API. domaine des méthodes qui "stocke des structures par classe telles que le pool de constantes d'exécution, les données des champs et des méthodes, et le code des méthodes et des constructeurs, y compris les méthodes spéciales utilisées dans l'initialisation des classes et des instances et l'initialisation des types d'interface". La spécification VM indique que, bien que le domaine des méthodes fait logiquement partie du tas, elle n'impose pas que la mémoire allouée dans la zone de méthode soit soumise au ramassage des ordures ou à d'autres comportements qui seraient associés à des structures de données normales allouées au tas.

10 votes

En fait, lorsque les classes sont chargées dans la VM, les constantes de chaîne de caractères seront copiées dans le tas, dans un pool de chaînes de caractères à l'échelle de la VM (dans le permgen, comme l'a dit Stephen C), puisque des chaînes de caractères identiques dans différentes classes doivent être le même objet String (par le JLS).

1 votes

Merci à tous pour vos réponses. J'ai beaucoup compris grâce à cette discussion. C'est un plaisir de vous connaître :)

5 votes

Paulo, c'est vrai pour la machine virtuelle de Sun, mais pas nécessairement pour toutes les implémentations de la JVM. Comme le mentionne la spécification de la JVM, bien que le pool de constantes d'exécution et la zone de méthodes fassent logiquement partie du tas, ils ne doivent pas nécessairement avoir le même comportement. Ce n'est qu'une différence sémantique mineure, vraiment :)

60voto

assylias Points 102015

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

Il est intéressant de noter que jusqu'à Java 7, le pool était dans l'espace permgen du heap sur la JVM hotspot mais il a été déplacé vers la partie principale du tas depuis Java 7 :

Zone : HotSpot
Synopsis : Dans le JDK 7, les chaînes internées ne sont plus allouées dans la génération permanente du tas Java, mais sont au contraire alloués dans la partie principale du tas de Java. (appelées jeunes et vieilles générations), ainsi que les autres objets créés par l'application. Ce changement se traduira par une augmentation des données résidant dans le tas principal de Java et une diminution des données dans la génération permanente, ce qui peut nécessiter un ajustement de la taille du tas. 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 importantes qui chargent de nombreuses classes ou qui font un usage intensif de la méthode String.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.

31voto

Stephen C Points 255558

Les chaînes de caractères ne sont pas stockées sur la pile. Jamais. En fait, aucun objet n'est stocké sur la pile.

Les littéraux de chaîne (ou plus précisément, les objets Chaîne qui les représentent) son étaient historiquement stockés dans un tas appelé le tas "permgen". (Permgen est l'abréviation de génération permanente).

Dans des circonstances normales, les littéraux String et la plupart des autres éléments du tas permgen sont accessibles "en permanence" et ne sont pas collectés. (Par exemple, les littéraux String sont toujours accessibles à partir des objets de code qui les utilisent). Cependant, vous pouvez configurer une JVM pour qu'elle tente de trouver et de collecter les classes chargées dynamiquement qui ne sont plus nécessaires, ce qui peut entraîner la collecte des littéraux String.

CLARIFICATION #1 - Je ne dis pas que Permgen n'a pas de CG. Il l'est, généralement lorsque la JVM décide d'exécuter une GC complète. Ce que je veux dire, c'est que String littéraux seront accessibles tant que le code qui les utilise sera accessible, et le code sera accessible tant que le classloader du code sera accessible, et pour les classloaders par défaut, cela signifie "pour toujours".

CLARIFICATION #2 - En fait, Java 7 et les versions ultérieures utilisent le tas régulier pour contenir le pool de chaînes. Ainsi, les objets String qui représentent les littéraux String et les chaînes internées sont en fait dans le tas régulier. (Voir la réponse de @assylias pour plus de détails).


Mais j'essaie toujours de trouver la frontière entre le stockage d'une chaîne de caractères littérale et une chaîne de caractères créée avec l'option new .

Il n'y a pas de "ligne fine". C'est vraiment très simple :

  • String Les objets qui représentent / correspondent aux littéraux de chaîne sont conservés dans le pool de chaînes.
  • String qui ont été créés par un String::intern sont détenus dans le pool de cordes.
  • Tous les autres String ne sont PAS conservés dans le pool de chaînes.

Il y a ensuite la question distincte de savoir où le pool de chaînes de caractères est "stocké". Avant Java 7, il s'agissait du tas permgen. À partir de Java 7, il s'agit du tas principal.

23voto

Trying Points 4092

Mise en commun des chaînes

La mise en commun de chaînes de caractères (parfois appelée aussi canonisation de chaînes de caractères) est une processus de remplacement de plusieurs objets String de même valeur mais de identité différente par un seul objet String partagé. Vous pouvez atteindre ce but en conservant votre propre Map (avec éventuellement des ou faibles, selon vos besoins) et en utilisant les valeurs de map comme valeurs canonisées. Ou vous pouvez utiliser la méthode String.intern() qui vous est fournie par le JDK.

A l'époque de Java 6, l'utilisation de String.intern() était interdite par de nombreuses personnes. normes en raison d'une forte possibilité d'obtenir une OutOfMemoryException si le le pooling devenait incontrôlable. L'implémentation de la mise en commun des chaînes par Oracle Java 7 a été considérablement modifiée. Vous pouvez consulter les détails dans http://bugs.sun.com/view_bug.do?bug_id=6962931 et http://bugs.sun.com/view_bug.do?bug_id=6962930 .

String.intern() en Java 6

Au bon vieux temps, toutes les chaînes internées étaient stockées dans le fichier PermGen - la partie de taille fixe du tas principalement utilisée pour stocker les classes chargées et le pool de chaînes. En plus des chaînes de caractères explicitement internées, le pool de chaînes de caractères PermGen contenait également toutes les chaînes littérales utilisées précédemment dans votre programme. (le mot important ici est "utilisées" - si une classe ou une méthode n'a jamais été chargée/appelée, les constantes qui y sont 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 - PermGen. PermGen a une taille fixe et ne peut pas être étendu au moment de l'exécution. d'exécution. Vous pouvez la définir en utilisant l'option -XX:MaxPermSize=96m. Pour autant que je sache la taille par défaut de PermGen varie entre 32M et 96M selon la plate-forme. la plate-forme. Vous pouvez augmenter sa taille, mais celle-ci sera toujours fixe. Une telle limitation a nécessité une utilisation très prudente de String.intern - il vaut mieux ne pas internaliser une entrée utilisateur incontrôlée en utilisant cette méthode. C'est pourquoi, à l'époque de Java 6, la mise en commun des chaînes de caractères était principalement mise en œuvre dans les cartes gérées manuellement. les cartes gérées manuellement.

String.intern() en Java 7

Les ingénieurs d'Oracle ont apporté une modification extrêmement importante à la chaîne de caractères dans Java 7 : le pool de chaînes de caractères a été déplacé vers le tas. Cela signifie que vous n'êtes plus limité par une zone de mémoire distincte de taille fixe. zone de mémoire distincte de taille fixe. Toutes les chaînes de caractères sont maintenant situées dans le tas, comme la plupart des autres objets ordinaires. objets ordinaires, ce qui vous permet de gérer uniquement la taille du tas tout en tout en ajustant votre application. Techniquement, ceci pourrait être une raison suffisante pour raison suffisante pour reconsidérer l'utilisation de String.intern() dans vos programmes Java 7. Mais il y a d'autres raisons.

Les valeurs du pool de chaînes sont collectées à la poubelle

Oui, toutes les chaînes de caractères dans le pool de chaînes de caractères de la JVM sont éligibles pour le garbage. s'il n'y a pas de référence à elles dans 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 sortie du champ d'application et qu'il n'y a pas d'autres références à celle-ci et qu'il n'y a pas d'autres références à celle-ci, elle sera récupérée dans le pool de chaînes de la JVM.

Étant éligible à la collecte des déchets et résidant dans le tas, une JVM semble être le bon endroit pour toutes vos chaînes de caractères, 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. le pool, les chaînes utilisées vous permettront d'économiser de la mémoire dans le cas où vous vous obtenez une chaîne égale à partir de l'entrée. Cela semble être une parfaite stratégie d'économie de mémoire ? Presque. Vous devez savoir comment le pool de chaînes est implémenté avant de prendre toute décision.

source.

-3voto

Zahid Hussain Points 7

Les chaînes de caractères sont immuables si nous ajoutons une chaîne de caractères à une chaîne de caractères existante, elle fera référence à une autre variable et l'ancienne variable sera mise à jour avec une nouvelle valeur et l'ancienne chaîne de caractères de la variable restera en mémoire. En fait, cette ancienne variable ne sera plus utilisée.

String a="zahid" ; // ceci fera maintenant partie du pool de constantes string parce que sa valeur est mise à jour.

a+="Hussain" ; // il s'agit d'une autre variable de type chaîne de caractères qui est créée comme un nouvel objet en mémoire car les chaînes de caractères sont immuables.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X