web-dev-qa-db-fra.com

GC libère-t-il de la mémoire sur le système d'exploitation?

Lorsque le garbage collector s'exécute et libère de la mémoire, cette mémoire revient-elle au système d'exploitation ou est-elle conservée dans le cadre du processus. J'avais la forte impression que la mémoire n'est jamais réellement restituée au système d'exploitation mais conservée dans le cadre de la zone/du pool de mémoire pour être réutilisée par le même processus.

Par conséquent, la mémoire réelle d'un processus ne diminuerait jamais. n article qui m'a rappelé que c'était ça et que Java's Runtime est écrit en C/C++ donc je suppose que la même chose s'applique?

Mise à jour
Ma question concerne Java. Je mentionne C/C++ car je suppose que l'allocation/désallocation de Java est effectuée par JRE en utilisant une certaine forme de malloc/delete

34
Jim

HotSpot JVM libère de la mémoire sur le système d'exploitation, mais le fait à contrecœur, car le redimensionnement du tas est coûteux et on suppose que si vous avez besoin de ce tas une fois, vous en aurez besoin à nouveau.

Vous pouvez le rendre plus agressif en définissant -XX:GCTimeRatio=19 -XX:MinHeapFreeRatio=20 -XX:MaxHeapFreeRatio=30, Ce qui lui permettra de consacrer plus de temps CPU à la collecte et de limiter la quantité de mémoire de segment allouée mais non utilisée après un cycle GC.

En supposant que vous utilisez un collecteur simultané, vous pouvez également définir -XX:InitiatingHeapOccupancyPercent=N Avec N sur une valeur faible pour permettre au GC d'exécuter des collections simultanées presque en continu, ce qui consommera encore plus de cycles CPU mais réduira le tas plus tôt. Ceci en général n'est pas une bonne idée, mais sur certains types de machines avec beaucoup de cœurs CPU de rechange mais manquant de mémoire, cela peut avoir du sens.

Si vous utilisez un collecteur avec un objectif de temps de pause par défaut (CMS ou G1), vous pouvez également assouplir cet objectif pour placer moins de contraintes sur le collecteur, ou vous pouvez passer au collecteur parallèle pour donner la priorité à l'empreinte sur les temps de pause.

De plus, avec Java 9 -XX:-ShrinkHeapInSteps Peut être utilisée pour appliquer de manière plus agressive le rétrécissement causé par les deux options précédentes. Bogue OpenJDK pertinent .

Notez que la réduction de la capacité et du comportement dépend du ramasse-miettes choisi. Par exemple, G1 n'a gagné que la capacité de restituer des morceaux inutilisés au milieu du tas avec jdk8u20, tandis que ZGC fait avec jdk1 et le collecteur epsilon ne le feront probablement jamais.
Donc, si vous souhaitez réduire le segment de mémoire, vous devez tester une version JVM et une configuration GC particulières.

La journalisation GC avec PrintAdaptiveSizePolicy peut également fournir des informations, par exemple lorsque la JVM essaie d'utiliser plus de mémoire pour que la jeune génération atteigne certains objectifs.

Il y a aussi JEP 346 , inclus dans OpenJDK 12, qui introduit la version mémoire Prompt pour G1GC avec l'option G1PeriodicGCInterval, Toujours au détriment de certains CPU supplémentaires. Il mentionne également des fonctionnalités similaires dans Shenandoah et OpenJ9 VM .

48
the8472

La JVM libère de la mémoire dans certaines circonstances, mais (pour des raisons de performances), cela ne se produit pas chaque fois que de la mémoire est récupérée. Cela dépend également de la JVM, du système d'exploitation, du garbage collector, etc. Vous pouvez surveiller la consommation de mémoire de votre application avec JConsole, VisualVM ou un autre profileur.

Voir aussi ceci rapport de bug lié

9
lbalazscs

Si vous utilisez le collecteur G1 et appelez System.gc () de temps en temps (je le fais une fois par minute), Java réduira de manière fiable le tas et restituera de la mémoire au système d'exploitation).

Certaines personnes moussent à la bouche chaque fois que vous mentionnez l'idée d'invoquer manuellement le ramasse-miettes - mais vous devez le faire si vous voulez un compactage fiable du tas.

Je recommande d'utiliser ces options combinées avec la suggestion ci-dessus pour une taille de processus résident très compacte:

-XX:+UseG1GC -XX:MaxHeapFreeRatio=30 -XX:MinHeapFreeRatio=10

J'utilise ces options quotidiennement depuis des mois avec une grande application (un système d'exploitation invité complet basé sur Java) avec des classes de chargement et de déchargement dynamiques - et le processus Java reste presque toujours entre 400 et 800 Mo.

Edit: JDK 12 aura le collecteur G1 retourner la mémoire à l'OS (sans appeler System.gc) "lorsque l'application est inactive". Ce dernier terme semble être défini pour les applications serveur, mais peut-être que cela fonctionnera aussi pour le bureau et/ou ils le rendront personnalisable.

3
Stefan Reich

cet article ici explique comment le GC fonctionne en Java 7. En résumé, il existe de nombreux récupérateurs différents. Habituellement, la mémoire est conservée pour le Java process et seuls certains GC le libèrent sur le système (sur demande je pense). Mais, la mémoire utilisée par le processus Java ne croîtra pas indéfiniment, comme il existe une limite supérieure définie par l'option Xmx (qui est généralement de 256 m, mais je pense que cela dépend du système d'exploitation/de la machine).

3