Quelqu'un peut-il m'expliquer pourquoi les machines virtuelles Java (je n'en ai pas vérifié trop, mais je n'en ai jamais vu une qui ne l'a pas fait de cette façon) doivent fonctionner sur une taille de segment fixe? Je sais qu'il est plus facile à implémenter sur un simple tas contigu, mais la JVM Sun a maintenant plus de dix ans, alors je m'attendrais à ce qu'ils aient eu le temps d'améliorer cela.
La nécessité de définir la taille maximale de la mémoire de votre programme au démarrage semble une telle chose dans les années 1960, puis il y a les mauvaises interactions avec la gestion de la mémoire virtuelle du système d'exploitation (récupération des données échangées par le GC, incapacité à déterminer la quantité de mémoire du processus Java) en utilisant vraiment du côté du système d'exploitation, d'énormes quantités d'espace virtuel gaspillées (je sais, vous ne vous souciez pas de vos fantastiques machines 48 bits ...)). Je suppose également que les diverses tentatives tristes de construire de petits systèmes d'exploitation à l'intérieur de la JVM (serveurs d'applications EE, OSGi) sont au moins en partie responsables de cette circonstance, car l'exécution de plusieurs processus Java sur un système entraîne invariablement un gaspillage de ressources car vous devez donnez à chacun d'eux la mémoire qu'il pourrait avoir à utiliser au maximum.
Étonnamment, Google n'a pas provoqué les tempêtes d'indignation que j'attendrais à ce sujet, mais ils ont peut-être été enterrés sous les millions de personnes découvrant la taille fixe du tas et l'acceptant juste pour un fait.
Réponses:
Vous avez tort. La taille de segment de mémoire des machines virtuelles Java n'est pas fixe, uniquement limitée:
La fixation d'une limite supérieure est nécessaire pour plusieurs raisons. Tout d'abord, il indique au ramasse-miettes quand il doit entrer en action. Deuxièmement, cela empêche la JVM de boucher la machine entière en consommant trop de mémoire. La taille de segment minimale est probablement utile pour réserver au moins la quantité de mémoire dont le programme a besoin, pour éviter qu'il ne manque de mémoire (car d'autres processus consomment trop).
la source
J'imagine que la réponse a quelque chose à voir avec l'héritage de Java. Il a été initialement conçu comme un langage à utiliser pour les systèmes embarqués, où les ressources sont évidemment limitées et vous ne voulez pas que les processus engloutissent simplement tout ce qui est disponible. Il facilite également l'administration du système, car il facilite la mise à disposition des ressources sur un serveur si vous pouvez définir des limites de ressources. Je vois que les dernières machines virtuelles Java semblent utiliser plusieurs tas non continus, bien que tout cela apparaisse bien sûr comme un seul tas à votre code.
(FWIW, vous deviez spécifier les besoins en mémoire d'un programme sous les versions MacOS pré-Darwin d'Apple [jusqu'au système 7 de toute façon, qui était la dernière que j'ai utilisée], ce qui était bien dans les années 80.)
la source
Vous devez donner le GC certains mécanisme pour lui dire quand s'exécuter, ou votre programme remplira tout l'espace mémoire virtuel. Il existe de nombreuses autres façons de déclencher le GC: le temps écoulé, le nombre d'allocations, le nombre d'affectations, probablement d'autres auxquelles je ne peux pas penser en ce moment. IMO, rien de tout cela n'est aussi bon que de simplement définir une limite de mémoire et d'exécuter GC lorsque l'espace alloué atteint cette limite.
La clé est de définir les limites correctes . Je regarde
-ms
"c'est la quantité de mémoire dont mon application a besoin", et-mx
que "elle ne doit jamais dépasser ce montant". Dans un déploiement en production, les deux doivent être proches sinon égaux, et ils doivent être basés sur des exigences réelles et mesurées.Vos inquiétudes concernant la mémoire virtuelle «gaspillée» sont déplacées: c'est virtuel, c'est (presque) gratuit. Oui, si le segment est trop volumineux, cela signifie que vous ne pouvez pas démarrer autant de threads ou charger autant de fichiers mappés en mémoire. Mais cela fait partie de la conception de l'application: vous avez des ressources rares, vous devez les partitionner de manière à permettre l'exécution de votre application. Dans un tas "de style C", qui se développera jusqu'à ce que vous atteigniez le sommet de la mémoire, le problème de base est le même, vous n'avez juste pas à y penser jusqu'à ce que vous ayez des ennuis.
La seule chose qu'un grand tas peut "gaspiller" est l'espace de swap, car tous les segments inscriptibles nécessitent un engagement de swap. Mais cela fait partie de la conception du système: si vous voulez que de nombreuses machines virtuelles Java s'exécutent sur la même boîte, augmentez votre swap ou réduisez leur allocation de tas. S'ils commencent à se débattre, alors vous essayez d'en faire trop avec le système; acheter plus de mémoire (et si vous utilisez toujours un processeur 32 bits, achetez un nouveau boîtier).
la source
Comme le dit user281377, vous spécifiez uniquement une limite supérieure de la quantité de mémoire que votre processus peut consommer. Bien sûr, l'application elle-même n'accaparera que l'espace dont elle a besoin.
Qu'il existe ou non une limite supérieure par défaut est une autre question, à la fois pour et contre.
la source