Un simple «Hello World» nécessite 10G de mémoire virtuelle sur une machine 64 bits contre 1G sur 32-bit?

En exécutant un programme Java simple sur notre machine de production, j’ai remarqué que ce programme mange plus de 10G virt. Je sais que la mémoire virtuelle n’est pas si pertinente, mais au moins j’aimerais comprendre pourquoi cela est nécessaire.

public class Main { public static void main(Ssortingng[] args) { System.out.println("Hello World!"); try { Thread.sleep(10000); } catch(InterruptedException e) { /* ignored */ } } } 

Heres ce que dit top quand je lance ce petit programme:

  PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 18764 myuser 20 0 10.2g 20m 8128 S 1.7 0.1 0:00.05 java 

Est-ce que quelqu’un sait pourquoi cela se produit?

uname -a dit:

 Linux m4fxhpsrm1dg 2.6.32-358.18.1.el6.x86_64 #1 SMP Fri Aug 2 17:04:38 EDT 2013 x86_64 x86_64 x86_64 GNU/Linux 

Sur une ancienne machine Linux à 32 bits, le même programme consum seulement 1 G virt. L’ancienne machine a 4 Go de RAM, la nouvelle 32 Go.

Les tailles par défaut pour le segment de mémoire initial et le segment de mémoire maximal sont définies en tant que pourcentage de la mémoire physique de la machine, dont un serveur de production a actuellement tendance à avoir beaucoup .

Vous pouvez choisir les deux via les options de ligne de commande -Xms et -Xmx .

La mémoire virtuelle n’a pas d’importance pour vous.

La différence de base entre 32 bits et 64 bits est que l’espace d’adressage en 64 bits est incroyablement grand. Si 10 GiB vous ressemble beaucoup, notez que .NET sur 64 bits peut utiliser des TiB de mémoire comme celui-ci. Pourtant, sur 32 bits, .NET est beaucoup plus conservateur (tout comme JVM) – l’espace d’adressage est de 4 Gio au total – ce n’est pas beaucoup.

Mais c’est sans importance – ça n’a pas d’importance. C’est simplement une chose qui simplifie grandement la programmation et n’a aucun effet négatif sur le système d’exploitation hôte. Cela crée un espace d’adressage continu pour la VM à utiliser, ce qui signifie que vous n’avez pas besoin de fragmenter le tas (ou pire, la stack, où c’est plus ou moins impossible – mais ceux-ci ont tendance à être seulement une MiB) vous avez besoin de plus de mémoire “réelle”. Lorsque vous validez enfin la mémoire virtuelle, celle-ci devient légèrement plus réelle – à ce moment-là, elle doit être plus ou moins sauvegardée par du stockage de données – que ce soit le fichier d’échange (swap) ou la RAM physique.

L’important, c’est que l’emplacement physique de la mémoire n’est pas nécessairement continu, mais cela se fait hors de votre scope, et le mappage est généralement très rapide. D’un autre côté, devoir, par exemple, indexer un tableau, qui est en réalité fragmenté sur 10 blocs de mémoire d’adresses virtuelles différents, c’est un travail (complètement inutile).

Donc là vous l’avez – la mémoire virtuelle est presque libre sur 64 bits. L’approche de base est “si c’est là, utilisez-le”. Vous ne limitez pas les autres applications et cela vous évite beaucoup de travail si vous finissez par l’utiliser. Mais jusqu’à ce moment-là, vous avez seulement une réservation. Cela ne se traduit en aucune mémoire physique. Vous ne payez pas pour les amis qui pourraient venir ce soir et vous asseoir à votre table, mais vous avez toujours la possibilité de s’asseoir s’ils arrivent – et ce n’est que lorsqu’ils arrivent finalement que vous êtes réellement “chargé”.

Voir cette question pour plus d’informations sur le comportement de Java sur différentes machines et avec différentes versions: Quelle est la taille de stack maximale par défaut pour la machine virtuelle Java de Sun à partir de Java SE 6? La taille de segment maximale détermine également la quantité de mémoire virtuelle réservée, car le segment de mémoire doit être un espace d’adressage continu. S’il n’était pas pré-réservé, il se peut que le segment de mémoire ne puisse pas s’étendre à cette valeur maximale, car quelqu’un d’autre a réservé une zone d’espace d’adressage à l’endroit où le segment doit se développer.

Ce n’est pas votre programme qui utilise cette mémoire, c’est la machine virtuelle Java réservant cette mémoire, quel que soit le programme chargé.

Il s’avère que sur une architecture informatique moderne utilisant l’adressage de mémoire virtuelle (où «l’espace mémoire» vu par une application ne concerne pas réellement la mémoire réellement allouée physiquement), la quantité de cet espace de mémoire virtuel “est donné à une application au démarrage. Cela ne signifie pas que cette quantité de mémoire a été allouée par le système.

Si une application voit un espace d’adresse virtuel de 10 Go, tout ce qu’elle envoie à l’application, c’est qu’elle peut utiliser des adresses mémoire jusqu’à 10 Go si elle le souhaite. Cependant, la mémoire n’est pas réellement allouée dans la RAM physique tant qu’elle n’est pas réellement écrite, et ceci est fait page par page, où une page est une section de mémoire de 4 Ko. L’espace d’adressage virtuel n’est que cela – complètement virtuel jusqu’à ce qu’il soit réellement utilisé.

Supposons qu’une application dispose de 10 Go d’espace d’adressage et commence à l’utiliser. Au fur et à mesure de l’écriture d’une nouvelle page de cette mémoire virtuelle, celle-ci demeurant inchangée, le système va, à un faible niveau, “mapper” cette page virtuelle sur une partie de la mémoire physique, puis l’écrire. Mais cette application elle-même ne doit pas se soucier de tels détails, elle agit simplement comme si elle avait un access complet à une zone de mémoire virtuelle.

Dans le cas d’applications Java, ce n’est pas l’application elle-même mais Java qui reçoit cet espace d’adressage et Java demande simplement un énorme espace d’adressage par défaut – la quantité demandée est calculée par rapport à la taille de la mémoire physique. tout doit être conservateur, mais juste pour des raisons pratiques – une application ne va probablement pas vouloir suffisamment de taille de tas pour mettre totalement un serveur à genoux, donc elle fonctionne en supposant que ce ne sera pas le cas. Comme je l’ai dit plus haut, cela ne signifie pas que beaucoup de choses sont “allouées” ou que le système a dû consacrer beaucoup de ressources à le faire.

Imaginez que vous êtes dans le secteur du stockage de documents. Vous avez une petite installation au milieu de la ville qui stocke des boîtes de papiers et un entrepôt beaucoup plus grand en dehors de la ville avec 1000 fois plus d’espace. Chaque boîte comporte une étiquette identifiant son contenu.

L’installation en ville est la mémoire principale. L’entrepôt est de l’espace disque.

Une allocation de mémoire virtuelle de 10 Go pour un nouveau processus ne signifie pas trouver de place pour 10 milliards de boîtes pour un nouveau client. Cela signifie imprimer 10 milliards d’étiquettes pour les boîtes avec des numéros d’identification contigus.

Ce n’est pas la quantité de mémoire physique utilisée par l’application. Une mémoire virtuelle utilisée par tous les processus peut être beaucoup plus importante que la quantité de RAM physique sur la machine, sans aucun problème évident.

Votre programme n’utilise PAS autant de mémoire. JVM / OS réserve cette mémoire, c’est-à-dire la limite UPTO que votre programme peut utiliser. En outre, comme une des réponses mentionne clairement. 32 bits et 64 bits n’ont rien à voir avec cela. 32 bits signifie que vous pouvez accéder à 2 ^ 32 emplacements de mémoire physique. et 64 bits signifie jusqu’à 2 ^ 64.