Résumé des bases de Java (88) - Réglage de la mémoire

Lien d'origine

Si vous voulez résoudre le débordement de mémoire, quels paramètres peuvent être définis dans le jvm? Je pense qu'il peut être utile de voir une partie de la description ci-dessous.

Idéalement, un programme Java peut très bien fonctionner en utilisant les paramètres par défaut de la JVM, donc en général, il n'est pas nécessaire de définir des paramètres JVM. Cependant, en raison de certains problèmes de performances (malheureusement, ces problèmes surviennent souvent), une certaine connaissance des paramètres JVM pertinents sera un bon partenaire dans notre travail. Dans cet article, nous présenterons quelques paramètres sur la gestion de la mémoire JVM. Connaître et comprendre ces paramètres sera très utile aux développeurs et au personnel d'exploitation et de maintenance.

Tous les algorithmes de gestion de la mémoire HotSpot et de garbage collection qui ont été développés sont basés sur la même division de mémoire de tas: la jeune génération (jeune génération) stocke les objets nouvellement alloués et plus jeunes, et l'ancienne génération (ancienne génération) stocke les objets de longue durée. De plus, la génération permanente stocke les objets qui doivent accompagner tout le cycle de vie de la JVM, comme la définition de classe de l'objet chargé ou le cache interne de l'objet String. Ensuite, nous supposerons que la mémoire du tas est divisée selon la stratégie classique des jeunes, des vieux et des permanents. Cependant, d'autres stratégies de partitionnement de la mémoire de tas sont également possibles, comme le nouveau garbage collector G1, qui brouille la distinction entre les jeunes et les anciennes générations. De plus, le processus de développement actuel semble indiquer que dans les futures versions de HotSpot JVM, il n'y aura pas de distinction entre l'ancienne génération et la génération permanente.

-Xms et -Xmx (ou: -XX: InitialHeapSize et -XX: MaxHeapSize)

-Xms et -Xmx sont sans doute les paramètres JVM les plus populaires, ils nous permettent de spécifier la taille de mémoire de tas initiale et maximale de la JVM. D'une manière générale, l'unité numérique de ces deux paramètres est Byte, mais en même temps, ils prennent également en charge l'utilisation de la notation abrégée, comme "k" ou "K" pour "kilo", "m" ou "M" pour " mega ", et" g "" Ou "G" signifie "giga". Par exemple, la commande suivante démarre une application Java nommée «MyApp» avec une mémoire de segment initiale de 128 Mo et une mémoire de segment maximale de 2 Go.

1 java -Xms128m -Xmx2g MyApp

En utilisation réelle, la taille de la mémoire du tas initialisée est généralement considérée comme la limite inférieure de la taille de la mémoire du tas. Cependant, la JVM peut ajuster dynamiquement la taille de la mémoire du tas au moment de l'exécution, donc théoriquement, nous pouvons voir que la taille de la mémoire du tas est plus petite que la taille de la mémoire du tas initiale. Mais même avec une très faible utilisation de la mémoire du tas, je n'ai jamais rencontré cette situation. Ce comportement sera pratique pour les développeurs et les administrateurs système, car nous pouvons obtenir une mémoire de tas de taille fixe en définissant "-Xms" et "-Xmx" à la même taille. -Xms et -Xmx sont en fait les abréviations de -XX: InitialHeapSize et -XX: MaxHeapSize. On peut aussi utiliser ces deux paramètres directement, ils ont le même effet:

1 $ java -XX:InitialHeapSize=128m -XX:MaxHeapSize=2g MyApp

Il convient de noter que toutes les sorties JVM sur la taille de mémoire initiale \ maximale du tas utilisent leurs noms complets: "InitialHeapSize" et "InitialHeapSize". Ainsi, lorsque vous interrogez la taille de la mémoire du tas d'une machine virtuelle Java en cours d'exécution, par exemple en utilisant le paramètre -XX: + PrintCommandLineFlags ou en effectuant une requête via JMX, vous devez rechercher les indicateurs «InitialHeapSize» et «InitialHeapSize» au lieu de «Xms» et «Xmx» .

-XX: + HeapDumpOnOutOfMemoryError et -XX: HeapDumpPath

Si nous ne pouvons pas définir une taille appropriée pour -Xmx (mémoire maximale du tas), nous pourrions être confrontés au risque de manque de mémoire (OutOfMemoryError), qui peut être l'une des bêtes les plus terrifiantes auxquelles nous sommes confrontés lors de l'utilisation de JVM. Comme l'a dit un autre article de blog sur ce sujet, la cause première de la fuite de mémoire doit être soigneusement localisée. En règle générale, l'analyse des instantanés de la mémoire du tas (Heap Dump) est une bonne méthode de positionnement. Si les instantanés de mémoire ne sont pas générés en cas de dépassement de mémoire, c'est vraiment dommage, en particulier pour le type de JVM qui a planté ou l'erreur n'apparaît que dans le situation sur un système de production qui fonctionne bien depuis des heures, voire des jours.

Heureusement, nous pouvons définir -XX: + HeapDumpOnOutOfMemoryError pour permettre à JVM de générer automatiquement des instantanés de mémoire de tas en cas de débordement de mémoire. Avec ce paramètre, nous allons gagner beaucoup de temps lorsque nous devons faire face à des exceptions de dépassement de mémoire. Par défaut, l'instantané de la mémoire du tas sera enregistré dans un fichier nommé java_pid <pid> .hprof dans le répertoire de démarrage JVM (ici <pid> est le numéro de processus du processus JVM). Vous pouvez également modifier le chemin de génération d'instantané de mémoire de tas par défaut en définissant -XX: HeapDumpPath = <chemin>. <path> peut être un chemin relatif ou absolu.

Bien que tout cela sonne bien, il y a une chose que nous devons garder à l'esprit. Le fichier d'instantané de mémoire de tas peut être très volumineux, en particulier lorsqu'une erreur de dépassement de mémoire se produit. Par conséquent, nous vous recommandons de spécifier le chemin de génération de l'instantané de mémoire du tas vers un emplacement disposant d'un espace disque suffisant.

-XX: OnOutOfMemoryError

Lorsque le débordement de mémoire se produit, nous pouvons même exécuter certaines instructions, comme l'envoi d'un e-mail pour avertir l'administrateur ou effectuer des travaux de nettoyage. Nous pouvons le faire avec le paramètre -XX: OnOutOfMemoryError, qui peut accepter une série de commandes et leurs paramètres. Ici, nous n'entrerons pas dans ses détails, mais nous en donnons un exemple. Dans l'exemple suivant, lorsqu'une erreur de dépassement de mémoire se produit, nous écrirons l'instantané de mémoire du tas dans le fichier /tmp/heapdump.hprof et exécuterons le script cleanup.sh dans le répertoire d'exécution de la JVM

1 $ java -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/heapdump.hprof -XX:OnOutOfMemoryError ="sh ~/cleanup.sh" MyApp

 -XX: PermSize et -XX: MaxPermSize

La génération permanente est une zone indépendante de la mémoire du tas, qui contient les représentations d'objets de toutes les classes chargées par la JVM. Afin d'exécuter correctement l'application, la JVM chargera de nombreuses classes (car elles reposent sur un grand nombre de bibliothèques tierces, qui à leur tour dépendent de plus de bibliothèques et doivent charger des classes à partir d'elles), ce qui nécessite une augmentation du taille de la génération permanente. Nous pouvons utiliser -XX: PermSize et -XX: MaxPermSize pour atteindre cet objectif. Parmi eux, -XX: MaxPermSize est utilisé pour définir la valeur maximale de la génération permanente, et -XX: PermSize est utilisé pour définir la taille initiale de la génération permanente. Voici un exemple simple:

1 $ java -XX:PermSize=128m -XX:MaxPermSize=256m MyApp

Veuillez noter que la taille de génération permanente définie ici ne sera pas incluse dans la taille de mémoire de tas définie avec le paramètre -XX: MaxHeapSize. En d'autres termes, la mémoire de génération permanente définie par -XX: MaxPermSize peut nécessiter plus de mémoire de segment que la mémoire de segment définie par le paramètre -XX: MaxHeapSize.

-XX: InitialCodeCacheSize et -XX: ReservedCodeCacheSize

Une zone mémoire intéressante mais souvent négligée de la JVM est le "cache de code", qui est utilisé pour stocker le code natif généré par des méthodes compilées. La mise en cache de code pose rarement des problèmes de performances, mais son impact peut être dévastateur une fois qu'il se produit. Si le cache de code est plein, la JVM imprimera un message d'avertissement et passera en mode interprété uniquement: le compilateur JIT est désactivé et le bytecode ne sera plus compilé en code machine. Par conséquent, l'application continuera à s'exécuter, mais la vitesse de fonctionnement sera réduite d'un ordre de grandeur, jusqu'à ce que quelqu'un remarque le problème. Tout comme les autres zones de mémoire, nous pouvons personnaliser la taille du cache de code. Les paramètres pertinents sont -XX: InitialCodeCacheSize et -XX: ReservedCodeCacheSize, et leurs paramètres sont les mêmes que ceux décrits ci-dessus, et ce sont tous des valeurs d'octets.

-XX: + UseCodeCacheFlushing

Si le cache de code continue de croître, par exemple en raison de fuites de mémoire causées par un déploiement à chaud, l'augmentation de la taille du cache de code ne fera que retarder son débordement. Afin d'éviter cette situation, nous pouvons essayer un nouveau paramètre intéressant: lorsque le cache de code est plein, laissez la JVM abandonner du code compilé. En utilisant le paramètre -XX: + UseCodeCacheFlushing, nous pouvons au moins éviter que la JVM ne passe en mode interprété uniquement lorsque le cache de code est plein. Cependant, je recommande toujours de résoudre la cause première du problème de cache de code dès que possible, comme découvrir la fuite de mémoire et la réparer.

Je suppose que tu aimes

Origine blog.csdn.net/lsx2017/article/details/114040368
conseillé
Classement