J'ai un problème avec une application Java fonctionnant sous Linux.
Lorsque je lance l'application, en utilisant la taille de segment maximale par défaut (64 Mo), je constate qu'en utilisant l'application tops, 240 Mo de mémoire virtuelle sont alloués à l'application. Cela crée des problèmes avec certains autres logiciels de l'ordinateur, qui sont relativement limités en ressources.
La mémoire virtuelle réservée ne sera pas utilisée de toute façon, si je comprends bien, car une fois que nous atteignons la limite de tas, un OutOfMemoryError
est lancé. J'ai exécuté la même application sous Windows et je vois que la taille de la mémoire virtuelle et la taille du tas sont similaires.
Existe-t-il de toute façon que je peux configurer la mémoire virtuelle utilisée pour un processus Java sous Linux?
Edit 1 : Le problème n'est pas le tas. Le problème est que si je définis un tas de 128 Mo, par exemple, Linux alloue toujours 210 Mo de mémoire virtuelle, ce qui n'est jamais nécessaire. **
Edit 2 : L'utilisation ulimit -v
permet de limiter la quantité de mémoire virtuelle. Si la taille définie est inférieure à 204 Mo, l'application ne s'exécutera pas même si elle n'a pas besoin de 204 Mo, seulement 64 Mo. Je veux donc comprendre pourquoi Java nécessite autant de mémoire virtuelle. Cela peut-il être changé?
Edit 3 : Il existe plusieurs autres applications en cours d'exécution dans le système, qui est intégré. Et le système a une limite de mémoire virtuelle (à partir des commentaires, des détails importants).
la source
Réponses:
Il s'agit d'une plainte de longue date avec Java, mais elle est largement dénuée de sens, et généralement basée sur la recherche des informations erronées. Le phrasé habituel est quelque chose comme "Hello World sur Java prend 10 mégaoctets! Pourquoi a-t-il besoin de ça?" Eh bien, voici un moyen de faire Hello World sur une JVM 64 bits prétendre prendre plus de 4 gigaoctets ... au moins par une forme de mesure.
Différentes façons de mesurer la mémoire
Sous Linux, la commande top vous donne plusieurs nombres différents pour la mémoire. Voici ce qu'il dit à propos de l'exemple Hello World:
La situation de Windows Task Manager est un peu plus compliquée. Sous Windows XP, il existe des colonnes «Utilisation de la mémoire» et «Taille de la mémoire virtuelle», mais la documentation officielle ne précise pas ce qu'elles signifient. Windows Vista et Windows 7 ajoutent plus de colonnes, et elles sont en fait documentées . Parmi celles-ci, la mesure "Working Set" est la plus utile; il correspond à peu près à la somme de RES et SHR sous Linux.
Comprendre la carte de mémoire virtuelle
La mémoire virtuelle consommée par un processus est le total de tout ce qui se trouve dans la carte de mémoire de processus. Cela inclut les données (par exemple, le tas Java), mais également toutes les bibliothèques partagées et les fichiers mappés en mémoire utilisés par le programme. Sous Linux, vous pouvez utiliser la commande pmap pour voir toutes les choses mappées dans l'espace de processus (à partir de maintenant, je ne ferai référence qu'à Linux, car c'est ce que j'utilise; je suis sûr qu'il existe des outils équivalents pour Les fenêtres). Voici un extrait de la carte mémoire du programme "Hello World"; l'ensemble de la carte mémoire comporte plus de 100 lignes, et il n'est pas rare d'avoir une liste de mille lignes.
Une explication rapide du format: chaque ligne commence par l'adresse mémoire virtuelle du segment. Ceci est suivi de la taille du segment, des autorisations et de la source du segment. Ce dernier élément est soit un fichier soit "anon", qui indique un bloc de mémoire alloué via mmap .
En partant du haut, nous avons
java
). C'est très petit; il ne fait que charger dans les bibliothèques partagées où le vrai code JVM est stocké.-Xmx
valeur; cela lui permet d'avoir un tas contigu. La-Xms
valeur est utilisée en interne pour indiquer la quantité de tas "en cours d'utilisation" au démarrage du programme et pour déclencher le garbage collection à l'approche de cette limite.StackOverFlowError
. Pour une vraie application, vous verrez des dizaines sinon des centaines de ces entrées répétées à travers la carte mémoire.Les bibliothèques partagées sont particulièrement intéressantes: chaque bibliothèque partagée a au moins deux segments: un segment en lecture seule contenant le code de la bibliothèque et un segment en lecture-écriture qui contient des données globales par processus pour la bibliothèque (je ne sais pas ce que le segment sans autorisation est; je ne l'ai vu que sur Linux x64). La partie en lecture seule de la bibliothèque peut être partagée entre tous les processus qui utilisent la bibliothèque; par exemple,
libc
dispose de 1,5M d'espace de mémoire virtuelle qui peut être partagé.Quand la taille de la mémoire virtuelle est-elle importante?
La carte de mémoire virtuelle contient beaucoup de choses. Une partie est en lecture seule, une partie est partagée et une partie est allouée mais jamais touchée (par exemple, presque tout le 4 Go de tas dans cet exemple). Mais le système d'exploitation est suffisamment intelligent pour ne charger que ce dont il a besoin, de sorte que la taille de la mémoire virtuelle est largement hors de propos.
Lorsque la taille de la mémoire virtuelle est importante, si vous utilisez un système d'exploitation 32 bits, vous ne pouvez allouer que 2 Go (ou, dans certains cas, 3 Go) d'espace d'adressage de processus. Dans ce cas, vous avez affaire à une ressource rare et devrez peut-être faire des compromis, comme réduire la taille du segment de mémoire afin de mapper en mémoire un fichier volumineux ou de créer de nombreux threads.
Mais, étant donné que les machines 64 bits sont omniprésentes, je ne pense pas qu'il faudra longtemps avant que la taille de la mémoire virtuelle ne soit une statistique complètement hors de propos.
Quand la taille définie par le résident est-elle importante?
La taille de l'ensemble résident est la partie de l'espace mémoire virtuelle qui se trouve réellement dans la RAM. Si votre RSS devient une partie importante de votre mémoire physique totale, il est peut-être temps de commencer à vous inquiéter. Si votre flux RSS prend toute votre mémoire physique et que votre système commence à échanger, il est grand temps de commencer à vous inquiéter.
Mais RSS est également trompeur, en particulier sur une machine légèrement chargée. Le système d'exploitation ne consacre pas beaucoup d'efforts à récupérer les pages utilisées par un processus. Il y a peu d'avantages à le faire, et la possibilité d'une erreur de page coûteuse si le processus touche la page à l'avenir. Par conséquent, la statistique RSS peut inclure de nombreuses pages qui ne sont pas utilisées activement.
Bottom Line
À moins que vous n'échangiez, ne vous inquiétez pas trop de ce que les différentes statistiques de la mémoire vous disent. Avec la mise en garde qu'un RSS toujours croissant peut indiquer une sorte de fuite de mémoire.
Avec un programme Java, il est beaucoup plus important de faire attention à ce qui se passe dans le tas. La quantité totale d'espace consommé est importante et vous pouvez prendre certaines mesures pour réduire cela. Plus important est le temps que vous passez dans la collecte des ordures et quelles parties du tas sont collectées.
L'accès au disque (c'est-à-dire à une base de données) coûte cher et la mémoire est bon marché. Si vous pouvez échanger l'un contre l'autre, faites-le.
la source
Il existe un problème connu avec Java et glibc> = 2.10 (inclut Ubuntu> = 10.04, RHEL> = 6).
Le remède est de fixer cet env. variable:
Si vous exécutez Tomcat, vous pouvez l'ajouter au
TOMCAT_HOME/bin/setenv.sh
fichier.Pour Docker, ajoutez ceci à Dockerfile
Il existe un article IBM sur la configuration de MALLOC_ARENA_MAX https://www.ibm.com/developerworks/community/blogs/kevgrig/entry/linux_glibc_2_10_rhel_6_malloc_may_show_excessive_virtual_memory_usage?lang=en
Ce billet de blog dit
Il y a aussi un bug JDK ouvert JDK -8193521 "glibc gaspille de la mémoire avec la configuration par défaut"
recherchez MALLOC_ARENA_MAX sur Google ou SO pour plus de références.
Vous voudrez peut-être également régler d'autres options malloc pour optimiser la faible fragmentation de la mémoire allouée:
la source
MALLOC_ARENA_MAX
peut ralentir la croissance de votre mémoire, mais pas résoudre entièrement le problème.La quantité de mémoire allouée au processus Java est à peu près à la hauteur de ce à quoi je m'attendrais. J'ai rencontré des problèmes similaires en exécutant Java sur des systèmes intégrés / à mémoire limitée. L'exécution de toute application avec des limites de VM arbitraires ou sur des systèmes qui ne disposent pas de quantités suffisantes de swap a tendance à se casser. Cela semble être la nature de nombreuses applications modernes qui ne sont pas conçues pour être utilisées sur des systèmes à ressources limitées.
Vous avez quelques options supplémentaires que vous pouvez essayer de limiter l'empreinte mémoire de votre JVM. Cela pourrait réduire l'empreinte mémoire virtuelle:
En outre, vous devez également définir votre -Xmx (taille de segment de mémoire maximale) sur une valeur aussi proche que possible de l' utilisation maximale de la mémoire réelle de votre application. Je crois que le comportement par défaut de la JVM consiste toujours à doubler la taille du segment de mémoire chaque fois qu'elle l'étend au maximum. Si vous commencez avec 32M de tas et que votre application culmine à 65M, le tas finira par croître de 32M -> 64M -> 128M.
Vous pouvez également essayer ceci pour rendre la machine virtuelle moins agressive à propos de la croissance du tas:
De plus, d'après ce que je me souviens d'avoir expérimenté cela il y a quelques années, le nombre de bibliothèques natives chargées a eu un impact énorme sur l'empreinte minimale. Le chargement de java.net.Socket a ajouté plus de 15 Mo si je me souviens bien (et je ne le fais probablement pas).
la source
La JVM Sun nécessite beaucoup de mémoire pour HotSpot et elle est mappée dans les bibliothèques d'exécution en mémoire partagée.
Si la mémoire est un problème, envisagez d'utiliser une autre machine virtuelle Java appropriée pour l'incorporation. IBM a j9, et il y a le "jamvm" Open Source qui utilise les bibliothèques de chemin de classe GNU. Sun a également la JVM Squeak en cours d'exécution sur les SunSPOTS, il existe donc des alternatives.
la source
Juste une pensée, mais vous pouvez vérifier l'influence d' une
ulimit -v
option .Ce n'est pas une solution réelle car cela limiterait l'espace d'adressage disponible pour tous les processus, mais cela vous permettrait de vérifier le comportement de votre application avec une mémoire virtuelle limitée.
la source
Une façon de réduire le segment de mémoire d'un système avec des ressources limitées peut être de jouer avec la variable -XX: MaxHeapFreeRatio. Il est généralement défini sur 70 et correspond au pourcentage maximal du segment de mémoire libre avant que le GC ne le rétrécisse. En le réglant sur une valeur inférieure, et vous verrez par exemple dans le profileur jvisualvm qu'un plus petit segment de tas est généralement utilisé pour votre programme.
EDIT: pour définir de petites valeurs pour -XX: MaxHeapFreeRatio, vous devez également définir -XX: MinHeapFreeRatio Par exemple
EDIT2: Ajout d'un exemple pour une application réelle qui démarre et effectue la même tâche, une avec des paramètres par défaut et une avec 10 et 25 comme paramètres. Je n'ai pas remarqué de réelle différence de vitesse, bien que java devrait en théorie utiliser plus de temps pour augmenter le tas dans le dernier exemple.
À la fin, le tas maximum est 905, le tas utilisé est 378
À la fin, le tas max est 722, le tas utilisé est 378
Cela a en fait un certain impact, car notre application s'exécute sur un serveur de bureau distant et de nombreux utilisateurs peuvent l'exécuter en même temps.
la source
Java 1.4 de Sun a les arguments suivants pour contrôler la taille de la mémoire:
http://java.sun.com/j2se/1.4.2/docs/tooldocs/windows/java.html
Java 5 et 6 en ont plus. Voir http://java.sun.com/javase/technologies/hotspot/vmoptions.jsp
la source
Non, vous ne pouvez pas configurer la quantité de mémoire requise par VM. Cependant, notez qu'il s'agit de mémoire virtuelle, non résidente, donc elle y reste sans danger si elle n'est pas réellement utilisée.
Alternativement, vous pouvez essayer une autre JVM puis une Sun, avec une empreinte mémoire plus petite, mais je ne peux pas vous conseiller ici.
la source