4
votes

Forcer JVM à libérer de la mémoire

J'ai amélioré mon code pour obtenir un meilleur résultat du ramasse-miettes.

Maintenant, lorsque j'appelle System.gc () , cela libère toute la mémoire. Mais quand je surveille l'utilisation de la mémoire sans appeler System.gc () , l'application réserve et utilise de plus en plus de mémoire.

Cela signifie-t-il que mes améliorations fonctionnent et que j'ai toutes mes références correctement et que je peux ignorer comment la JVM libère de la mémoire par elle-même. Ou y a-t-il d'autres problèmes dans mon code qui sont les raisons pour lesquelles la JVM réserve plus de mémoire sans exécuter le ramasse-miettes.


0 commentaires

4 Réponses :


1
votes

Il n'y a aucun moyen de forcer JVM à libérer de la mémoire, System.gc () n'est qu'un indice. C'est à GC de gérer la mémoire (notez qu'il existe différents types de mémoire, par exemple tas, méta-espace, hors tas). Chaque algorithme GC a plusieurs paramètres de configuration que vous pouvez modifier, mais aucun des deux ne vous donnera la possibilité de libérer de la mémoire à la demande.

La JVM réserve de la mémoire au démarrage et demande de la mémoire supplémentaire au système d'exploitation jusqu'à ce qu'elle atteigne les limites configurées. Il le fait par incréments de blocs, demandant des Mo ou plus de mémoire à la fois, car demander de la mémoire à partir du système d'exploitation octet par octet serait très inefficace.


2 commentaires

Je sais que ce n'est qu'un indice. Mais ma question était quand System.gc () libère de la mémoire, cela signifie-t-il que j'ai toutes mes références? Parce que le jvm ne libère pas vraiment la mémoire par lui-même.


Si vous demandez quand la mémoire sera renvoyée au système d'exploitation, consultez stackoverflow.com/a/324505/1602555



2
votes

Dépend du GC utilisé par votre JVM. Si c'est JDK9 alors c'est probablement G1 qui est `` gourmand '' en termes de consommation de mémoire, Donc, selon la façon dont vous vérifiez la mémoire utilisée, cela peut sembler occuper beaucoup de mémoire (alors que cela consiste à la réserver et à utiliser / libérer dynamiquement / à la demande.

Vous pouvez utiliser

https://docs.oracle.com /javase/8/docs/technotes/tools/unix/jstat.html

pour vérifier la consommation de mémoire.

Et comme pour l'analyse GC et la consommation de mémoire, vérifiez ce qui suit: Problèmes d'utilisation élevée de la mémoire avec le garbage collector G1 + https: //www.javacodegeeks. com / 2017/11 / minimiser-l'utilisation-de-la-mémoire-java-right-garbage-collector.html


1 commentaires

Merci, je vais jeter un oeil.



2
votes

La mémoire inutilisée est de la mémoire gaspillée.

Pourquoi voulez-vous appeler explicitement System.gc () . À mon humble avis, vous ne devriez jamais l'appeler et laisser à la JVM le soin de décider quand exécuter GC. (JVM peut prendre de meilleures décisions que vous si vous êtes novice. Appelez System.gc () uniquement lorsque vous savez vraiment ce que vous faites.) C'est généralement un mauvaise pratique pour appeler System.gc () .

System.gc () est juste une requête / un conseil à la JVM pour exécuter GC. Cela ne signifie en aucun cas que GC fonctionnera certainement.

Vous pouvez avoir des fuites de mémoire en Java, mais ce n'est certainement pas la chose à regarder dans votre cas, car comme vous l'avez mentionné lorsque vous appelez System.gc () , vous pouvez voir de la mémoire se libérer vers le haut. (Donc ce n'est pas le cas que vous ayez toujours la référence des objets inutilisés qui peuvent empêcher GC de nettoyer ces objets.)

Pourquoi pensez-vous que c'est un problème avec votre code? Il peut arriver qu'aucune mémoire supplémentaire ne soit nécessaire ou si de la mémoire est nécessaire, vous en avez déjà beaucoup (et pour parler en termes simples, GC ne libère pas de mémoire car il reste encore beaucoup à exécuter pour le programme - alors pourquoi GC devrait-il se donner la peine d'effacer la mémoire?).


3 commentaires

Merci pour votre réponse. Cependant, je ne veux pas utiliser System.gc (). Je l'ai utilisé uniquement comme un outil pour voir si la mémoire sera libérée du tout. Il y avait un problème avec mon code mais je l'ai résolu maintenant. Mais je me demandais pourquoi la JVM ne libère pas la mémoire par elle-même ou pourquoi il faut si longtemps pour la libérer.


Le garbage collection passe du temps de calcul pour gagner de l'espace utilisable. Il est loin d'être clair qu'il est dans l'intérêt du «programme moyen» de vouloir ce compromis particulier.


@Dennis la JVM «libère» rarement de la mémoire. La plupart du temps, le garbage collection identifiera la mémoire inutilisée, au seul effet que votre programme de surveillance vous la montrera comme inutilisée. Les systèmes d'exploitation modernes ne dépendent pas non plus de la libération de mémoire. La mémoire est virtualisée et si un autre programme a besoin de mémoire physique, il peut l'obtenir que la mémoire soit libérée ou non. Donc, cette réponse l'a cloué, «la mémoire inutilisée est de la mémoire gaspillée» et ni la JVM ni le système d'exploitation ne dépenseront des ressources pour simplement vous présenter un plus grand nombre de «mémoire libre». C’est juste un chiffre, pas une chose significative.



1
votes

Il y a bien sûr une possibilité que vous ayez une fuite de mémoire, ce qui signifie que votre programme continue d'allouer de la mémoire sans jamais la libérer. (Par exemple, dans une liste ou une carte qui ne cesse de s'allonger.) Vous aurez besoin d'un profileur de mémoire pour vous assurer que vous ne souffrez pas d'une telle situation.

À part cela, je ne m'inquiéterais pas si la machine virtuelle semble continuer à allouer de la mémoire sans la libérer. C'est ainsi que fonctionnent les VM modernes, en particulier en mode «client»: tant qu'il y aura beaucoup de mémoire libre, elles ne perdront pas de temps avec le ramasse-miettes. Si la limite de mémoire est approchée, c'est à ce moment que le garbage collector se déclenchera. (Le mode "client" contre "serveur" est un argument JVM, vous pouvez l'expérimenter si vous le souhaitez, plus d'infos ici: Réel différences entre "java -server" et "java -client"? )

Autre que cela, ce que vous pouvez faire est:

a) assurez-vous que votre mécanisme d'exécution d'un GC complet exécute réellement un GC complet. Le meilleur mécanisme que je connaisse (qui n'est pas garanti de fonctionner, mais cela semble fonctionner pour autant que je sache) est d'allouer un objet référencé uniquement via une référence souple, puis de continuer à appeler GC jusqu'à ce que la référence souple devienne nulle .

b) lors d'une exécution de débogage, (disons, si les assertions sont activées,) continuez à déclencher un GC complet sur un thread séparé toutes les quelques secondes. Ensuite, si vous regardez la mémoire consommée par la machine virtuelle, elle doit rester à peu près constante. Sinon, vous avez une fuite de mémoire.


0 commentaires