Java "Impossible de réserver suffisamment d'espace pour le tas d'objects" même s'il y a suffisamment de RAM

J'ai actuellement quelques problèmes avec Java. Il ne démarrera pas en raison de problèmes de tas. Mais j'ai plus de 9 GB sans RAM (ou même 16 GB si vous supposez que le cache serait vide). C'est l'erreur que je reçois (et la command free )

 root@server: ~ # java Error occurred during initialization of VM Could not reserve enough space for object heap Error: Could not create the Java Virtual Machine. Error: A fatal exception has occurred. Program will exit. root@server: ~ # free total used free shared buffers cached Mem: 25165824 15941148 9224676 0 0 7082176 -/+ buffers/cache: 8858972 16306852 Swap: 0 0 0 

Je cours un Debian 64 bits sur un server virtualisé. Le logiciel de virtualisation est OpenVZ. Ceci est ma version Java (je peux exécuter cette command après avoir arrêté deux de mes machines virtuelles (4 en cours d'exécution)) :

 root@server: ~ # java -version java version "1.7.0_45" Java(TM) SE Runtime Environment (build 1.7.0_45-b18) Java HotSpot(TM) 64-Bit Server VM (build 24.45-b08, mixed mode) 

Que puis-je faire?


Comme demandé:

 root@server: ~ # cat /proc/meminfo MemTotal: 25165824 kB MemFree: 11723412 kB Cached: 4597552 kB Active: 9692308 kB Inactive: 3322544 kB Active(anon): 7411960 kB Inactive(anon): 1005340 kB Active(file): 2280348 kB Inactive(file): 2317204 kB Unevictable: 0 kB Mlocked: 0 kB SwapTotal: 0 kB SwapFree: 0 kB Dirty: 960 kB Writeback: 0 kB AnonPages: 8417300 kB Shmem: 21504 kB Slab: 427452 kB SReclaimable: 383424 kB SUnreclaim: 44028 kB 

Reguest2:

 root@server: ~ # cat /proc/user_beancounters Version: 2.5 uid resource held maxheld barrier limit failcnt 10023468: kmemsize 399250512 506245120 5053325720 5558658292 0 lockedpages 0 8 246744 246744 0 privvmpages 6005602 6291447 6291456 6291456 221 shmpages 8576 8608 579124 579124289562 0 dummy 0 0 9223372036854775807 9223372036854775807 0 numproc 598 1236 30000 30000 0 physpages 4634494 6291456 6291456 6291456 0 vmguarpages 0 0 6291456 9223372036854775807 0 oomguarpages 1529371 2144671 6291456 9223372036854775807 0 numtcpsock 62 164 30000 30000 0 numflock 25 39 1000 1100 0 numpty 13 24 512 512 0 numsiginfo 10 75 1024 1024 0 tcpsndbuf 3330352 4153232 1179110194 1684441906 0 tcprcvbuf 1216896 34410032 1179110194 1684441906 0 othersockbuf 270504 537552 589555096 1094886808 0 dgramrcvbuf 0 67048 589555096 589555096 0 numothersock 287 333 30000 30000 0 dcachesize 355559855 446054103 1103879952 1136996352 0 numfile 4766 7745 250000 250000 0 dummy 0 0 9223372036854775807 9223372036854775807 0 dummy 0 0 9223372036854775807 9223372036854775807 0 dummy 0 0 9223372036854775807 9223372036854775807 0 numiptent 14 14 1000 1000 0 root@server: ~ # java Error occurred during initialization of VM Could not reserve enough space for object heap Error: Could not create the Java Virtual Machine. Error: A fatal exception has occurred. Program will exit. root@server: ~ # cat /proc/user_beancounters Version: 2.5 uid resource held maxheld barrier limit failcnt 10023468: kmemsize 399246622 506245120 5053325720 5558658292 0 lockedpages 0 8 246744 246744 0 privvmpages 6005601 6291447 6291456 6291456 233 shmpages 8576 8608 579124 579124289562 0 dummy 0 0 9223372036854775807 9223372036854775807 0 numproc 598 1236 30000 30000 0 physpages 4635460 6291456 6291456 6291456 0 vmguarpages 0 0 6291456 9223372036854775807 0 oomguarpages 1529376 2144671 6291456 9223372036854775807 0 numtcpsock 64 164 30000 30000 0 numflock 25 39 1000 1100 0 numpty 13 24 512 512 0 numsiginfo 10 75 1024 1024 0 tcpsndbuf 3365232 4153232 1179110194 1684441906 0 tcprcvbuf 1249664 34410032 1179110194 1684441906 0 othersockbuf 270504 537552 589555096 1094886808 0 dgramrcvbuf 0 67048 589555096 589555096 0 numothersock 287 333 30000 30000 0 dcachesize 355559855 446054103 1103879952 1136996352 0 numfile 4768 7745 250000 250000 0 dummy 0 0 9223372036854775807 9223372036854775807 0 dummy 0 0 9223372036854775807 9223372036854775807 0 dummy 0 0 9223372036854775807 9223372036854775807 0 numiptent 14 14 1000 1000 0 

OpenVZ et memory

Le failcnt va sur les privvmpages , donc votre conteneur est incapable d'allouer plus d'espace memory virtuel de l'hôte:

 root@server: ~ # cat /proc/user_beancounters Version: 2.5 uid resource held maxheld barrier limit failcnt privvmpages 6005601 6291447 6291456 6291456 >233< physpages 4635460 6291456 6291456 6291456 0 vmguarpages 0 0 6291456 9223372036854775807 0 oomguarpages 1529376 2144671 6291456 9223372036854775807 0 

Notez que la memory virtuelle ! = Mémoire physique. Les process peuvent allouer quelque part autour de la quantité de memory virtuelle adressable (32 bits ~ 2G – 4G, 64 bits 8 To – 256 To), mais cela ne signifie pas que les pages memory physiques sont utilisées (une page étant un morceau de memory de 4 Ko).

physpages est le nombre de pages de memory physiques que votre conteneur peut utiliser.
oomguarpages est les pages de memory garantie que le conteneur recevra lorsque l'hôte est limité par la memory.
privvmpages est le nombre de pages de memory virtuelle que votre conteneur peut utiliser
vmguarpages est la quantité de memory virtuelle garantie de la même manière

Java

Oracle Java alloue toujours une partie contiguë de la memory virtuelle. Exécuter java sans arguments sur une boîte donne 5M de memory réelle utilisée ( RSS ), mais 660M d'espace VM alloué ( VSZ ):

  PID COMMAND VSZ RSS 20816 java 667496 4912 

En regardant les segments de memory pour le process java dans son file smaps montre un bloc d'environ smaps alloué, le rest est des files mappés en memory et des trucs java normaux.

Sur un système en place depuis un certain time, l'espace disponible sur la machine virtuelle est fragmenté au fur et à mesure que les process utilisent / libèrent des parties de celui-ci. Un grep Vmalloc /proc/meminfo vous donnera VmallocChunk qui est le plus grand morceau gratuit actuellement disponible. Si cela est faible, le système va essayer d'allouer plus de java quand java request, après tout, il est pratiquement illimité sur une boîte de 64 bits.

Réparer

Dites à votre hôte de configurer les privvmpages et vmguarpages beaucoup plus haut. Il n'est pas nécessaire qu'ils soient identiques à la memory physique car cela affecte le fonctionnement de la memory Linux

Vous pourriez peut-être contourner temporairement le problème en supprimant votre cache de files echo 1 > /proc/sys/vm/drop_caches mais ce n'est que temporaire.

Vous pouvez limiter le morceau de memory que java tente d'allouer à l'exécution avec un minimum de Xms ou en cours d'exécution avec Xmx maximum. Exécuter java avec ces options sur ma machine:

 java -Xms10M -Xmx10M 

réduit la taille virtuelle totale à 140 Mo ou plus avec uniquement un bloc contigu de 10 Mo pour le tas java alloué.

Dans notre cas, il a permis de limiter la taille du tas que la VM tente de réserver au démarrage.

Par exemple sur la command line:

export _JAVA_OPTIONS = '- Xms64M -Xmx128m'

ou pour Tomcat dans [TOMCAT_HOME] /bin/setenv.sh

#! / bin / sh

JAVA_OPTS = "- Xms64M -Xmx256M"

(Notez le trait de soulignement supplémentaire sur la command line.)

L'explication de notre fournisseur est:

  • la machine virtuelle Java calcule une taille de segment initiale au démarrage
  • ce calcul est basé sur la RAM disponible.
  • certaines installations java sur des servers virtuels privés (VPS) ne reflètent pas les contraintes de memory du VPS lors du calcul de la taille initiale du tas. Au lieu de cela, ils basent leur calcul sur la taille de la memory du système d'hébergement. Ce qui peut conduire à une quantité de memory libre qui n'est pas disponible sur le VPS.
  • lorsque vous fournissez une taille de segment initiale via JAVA_OPTS, la machine virtuelle utilise ces valeurs et n'essaie pas de calculer elle-même.

Vous devez probablement changer la taille du tas java par défaut, essayez ces arguments:

 -Xms<size> set initial Java heap size -Xmx<size> set maximum Java heap size -Xss<size> set java thread stack size 

par exemple:

 java -Xms64m -Xmx1512m 

Ce fil peut être utile

Vérifiez également le ulimit (ulimit permet de contrôler les ressources disponibles pour le shell et les process démarrés par celui-ci):

 ulimit -a 

Vous pourriez juste être hors de la memory virtuelle.

Vous vous concentrez sur l'utilisation de la RAM (ou son manque), mais vos JVM existantes réservent de la memory virtuelle, pas de la RAM. Tant que les pages réservées de la memory ne sont pas accessibles, il n'y a pas d'utilisation de RAM signalée.

Tandis que Linux masque habituellement ce problème par ses parameters de sur-engagement, il est fort possible que le fait que vous exécutiez un environnement virtualisé au niveau du operating system réduise / désactive l'engagement ou définisse un plafonnement du contrôle des ressources de memory virtuelle.

Sur une instance de operating system standard (pas sur un conteneur), le moyen le plus simple de contourner ce problème consiste à append un échange qui permettra à la memory réservée de ne pas gaspiller de RAM. Sur un conteneur, le moyen de surmonter le problème peut également nécessiter l'augmentation de la memory virtuelle disponible globalement, mais plus généralement, il suffit d'accorder plus de memory virtuelle au conteneur.