29 votes

Comment Java (JVM) alloue-t-il la pile pour chaque thread ?

Une application Java démarre avec un seul tas 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 tas et -Xss pour contrôler la taille de la pile.

Si je comprends bien, le tas créé devient une mémoire "gérée" de la JVM et tous les objets créés y sont placés.

Mais comment fonctionne la création de la pile ? Java crée-t-il une pile pour chaque thread lors de sa création ? Si oui, où se trouve exactement la pile dans la mémoire ? Elle ne se trouve certainement pas dans le tas "géré".

La JVM crée-t-elle la pile à partir de la mémoire native ou pré-alloue-t-elle une section de la zone 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 certaines choses à propos des piles de fils que l'équipe du Spécification Java nous dit. Entre autres choses :

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

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

  • La spécification permet aux piles de la machine virtuelle Java d'avoir une taille fixe ou de s'étendre et se contracter dynamiquement selon les besoins du calcul.

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

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

Dans Java SE 6, la valeur par 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 l'exécutant avec l'option -Xss. ... 64k est la quantité minimale d'espace de pile autorisée par thread.

  • JRockit alloue une mémoire séparée du tas où se trouvent les piles. (Source)

Notez que la JVM utilise plus de mémoire que le simple tas. Par exemple, les méthodes Java, les piles de threads et les handles natifs sont alloués dans une mémoire distincte du tas, tout comme 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 fils Java dans HotSpot est gérée par le logiciel, ce n'est pas une pile de fils native du système d'exploitation. (Source)

Elle utilise une pile logicielle distincte pour transmettre 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, dont il n'est pas garanti qu'elles soient toujours conservées dans les registres matériels. La gestion de ces structures de l'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 au runtime de la JVM (par exemple, le chargement des classes). (Source) .

  • Il est intéressant de noter que même les objets alloués peuvent parfois être situés sur la pile au lieu du tas pour optimiser les performances. (Source)

Les JVM peuvent utiliser une technique appelée "escape analysis", qui leur permet de savoir que certains objets restent confinés à un seul thread pendant toute leur durée de vie, et que cette durée est limitée par la durée de vie d'un cadre de pile donné. Ces objets peuvent être alloués en toute sécurité sur la pile plutôt que sur le tas.

Et parce qu'une image vaut mille mots, en voici une tirée de James Bloom Java memory


Je réponds maintenant à certaines de vos questions :

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

Ce n'est pas le cas. Peut être facilement prouvé par contradiction en créant un nombre variable de fils. Il fait quelques hypothèses sur le nombre maximal de fils et la taille de la pile de chaque fil. C'est pourquoi vous risquez de manquer de mémoire (et non de mémoire de tas !) si vous allouez trop de threads.

Java crée-t-il une pile pour chaque thread lors de sa création ?

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

Si oui, où se trouve exactement la pile sur la mémoire ? Elle ne se trouve certainement pas dans le tas "géré".

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

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

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

4voto

Daniel Points 2018

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

Autres lectures .

Donc, pour répondre à vos questions :

Java crée-t-il une pile pour chaque thread lors de sa création ?

Oui.

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

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

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

Ce n'est pas le cas.

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

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

EDIT :

Tout ce qui précède se réfère à Jrockit JVM, bien que je trouve difficile de croire que d'autres JVM seraient différentes sur des questions aussi 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