29 votes

Comment Java (JVM) alloue-t-il une pile à chaque thread ?

Une application Java démarre avec un seul heap pour tous les threads. Chaque thread a sa propre pile.

Lorsqu'une application Java est lancée, nous utilisons l'option JVM -Xms et -Xmx pour contrôler la taille du heap et -Xss pour contrôler la taille de la pile.

Je suis de l'avis que le heap créé devient une mémoire "gérée" de la JVM et que tous les objets créés y sont placés.

Mais comment fonctionne la création de la pile? Est-ce que Java créé une pile pour chaque thread lors de sa création? Si c'est le cas, où exactement la pile se trouve-t-elle en mémoire? Ce n'est certainement pas dans le heap "géré".

Est-ce que la JVM crée la pile à partir de la mémoire native ou pré-alloue-t-elle une section de la zone de mémoire gérée pour la pile? Si oui, comment la JVM sait-elle combien de threads seront créés?

46voto

Mifeet Points 2182

Il y a quelques choses sur les piles de threads que la spécification Java nous dit. Entre autres :

  • Chaque thread de la machine virtuelle Java a une pile privée de la machine virtuelle Java, créée en même temps que le thread.

  • Parce que la pile de la machine virtuelle Java n'est jamais manipulée directement sauf pour pousser et retirer des cadres, les cadres peuvent être alloués en tas. La mémoire pour une pile de la machine virtuelle Java n'a pas besoin d'être contiguë.

  • La spécification autorise les piles de la machine virtuelle Java à être de taille fixe ou à s'étendre et se contracter dynamiquement selon les besoins du calcul.

Maintenant, si nous nous concentrons sur les implémentations JVM telles que HotSpot, nous pouvons obtenir plus d'informations. Voici quelques faits que j'ai collectés auprès de différentes sources :

  • La taille minimale de la pile dans HotSpot pour un thread semble être fixe. C'est pour cela que l'option -Xss mentionnée est utilisée. (Source)

Dans Java SE 6, le défaut sur Sparc est de 512k dans la VM 32 bits et de 1024k dans la VM 64 bits. ... Vous pouvez réduire la taille de votre pile en exécutant avec l'option -Xss. ... 64k est la quantité minimale d'espace de pile autorisée par thread.

  • JRockit alloue de la mémoire séparément de la pile où les piles sont situées. (Source)

Remarquez que la JVM utilise plus de mémoire que simplement le tas. Par exemple, les méthodes Java, les piles de threads et les poignées natives sont allouées dans une mémoire distincte du tas, ainsi que les structures de données internes de la JVM.

  • Il existe une correspondance directe entre un thread Java et un thread OS natif dans HotSpot. (Source).

  • Mais la pile de threads Java dans HotSpot est gérée par logiciel, ce n'est pas une pile de threads native OS. (Source)

Il utilise une pile de logiciel distincte pour passer les arguments Java, tandis que la pile C native est utilisée par la VM elle-même. Un certain nombre de variables internes de la JVM, telles que le compteur de programme ou le pointeur de pile pour un thread Java, sont stockées dans des variables C, qui ne sont pas garanties d'être toujours conservées dans les registres matériels. La gestion de ces structures d'interpréteur logiciel consomme une part considérable du temps d'exécution total.

  • La JVM utilise également la même pile de threads Java pour les méthodes natives et les appels d'exécution de la JVM (par exemple le chargement de classe). (Source).

  • Intéressant, même les objets alloués peuvent parfois être situés sur la pile plutôt que sur le tas en tant qu'optimisation de performance. (Source)

Les JVM peuvent utiliser une technique appelée analyse d'évasion, par laquelle elles peuvent déterminer que certains objets restent confinés à un seul thread pendant toute leur durée de vie et que cette durée de vie est limitée par la durée de vie d'un cadre donné. De tels objets peuvent être en toute sécurité alloués sur la pile au lieu du tas.

Et comme une image vaut mille mots, voici une de James Bloom Mémoire Java


Maintenant répondant à certaines de vos questions :

Comment la JVM sait-elle combien de threads seront créés ?

Elle ne le sait pas. Cela peut être facilement prouvé par contradiction en créant un nombre variable de threads. Elle fait certaines hypothèses sur le nombre maximum de threads et la taille de la pile de chaque thread. C'est pourquoi vous pouvez manquer de mémoire (sans signifier la mémoire du tas !) si vous allouez trop de threads.

Java crée-t-il une pile pour chaque thread lorsqu'il est créé ?

Comme mentionné précédemment, chaque thread de la machine virtuelle Java a une pile privée de la machine virtuelle Java, créée en même temps que le thread. (Source).

Si oui, où exactement se trouve la pile dans la mémoire ? Ce n'est certainement pas dans le tas "géré".

Comme indiqué ci-dessus, la spécification Java permet à la mémoire de la pile d'être stockée sur le tas, techniquement parlant. Mais au moins la JVM JRockit utilise une partie de mémoire différente.

La JVM crée-t-elle la pile à partir de la mémoire native ou pré-alloue-t-elle une section de la zone de mémoire gérée pour la pile ?

La pile est gérée par la JVM car la spécification Java prescrit comment elle doit se comporter : Une pile de la machine virtuelle Java stocke des cadres (§2.6). Une pile de la machine virtuelle Java est analogue à la pile d'un langage conventionnel. Une exception sont les piles de méthodes natives utilisées pour les méthodes native. Plus à ce sujet à nouveau dans la spécification.

4voto

Daniel Points 2018

La JVM utilise plus de mémoire que juste le tas. Par exemple, les méthodes Java, les piles de threads et les gestionnaires natifs sont alloués en mémoire séparée du tas, ainsi que les structures de données internes de la JVM.

Lire la suite.

Donc pour répondre à vos questions:

Est-ce que Java crée une pile pour chaque thread lorsqu'il est créé?

Oui.

Si oui, où se trouve exactement la pile en mémoire?

Dans la mémoire allouée par la JVM, mais pas sur le tas.

Si oui, comment la JVM sait combien de threads seront créés?

Elle ne le sait pas.

Vous pouvez en créer autant que vous le souhaitez jusqu'à ce que vous ayez atteint la limite de votre mémoire JVM et obteniez

Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread

EDIT:

Tout ce qui précède se rapporte à la JVM Jrockit, même si je trouve difficile à croire que les autres JVM seraient différentes sur de telles questions fondamentales.

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