Comment trouver une fuite de mémoire Java

Comment trouver une fuite de mémoire en Java (en utilisant, par exemple, JHat)? J'ai essayé de charger le tas de déchets dans JHat pour prendre un look basique. Cependant, je ne comprends pas comment je suis supposé être capable de trouver la référence racine ( ref ) ou quel que soit son nom. Fondamentalement, je peux dire qu'il y a plusieurs centaines de mégaoctets d'entrées de table de hachage ([java.util.HashMap$l'Entrée ou quelque chose comme ça), mais les cartes sont utilisées partout dans l'endroit... Est-il un moyen de recherche pour les grandes cartes, ou peut-être trouver les racines générales de grands arbres d'objet?

[Edit] Ok, j'ai lu les réponses jusqu'à présent mais disons que je suis un bâtard bon marché (ce qui signifie que je suis plus intéressé à apprendre à utiliser JHat que de payer pour JProfiler). De plus, JHat est toujours disponible puisqu'il fait partie du JDK. A moins qu'il n'y ait pas d'autre solution que la force brute, mais je n'arrive pas à croire que ce soit le cas.

aussi, je ne pense pas que je serai en mesure de faire modifier (ajout de la journalisation de toutes les tailles de carte ) et l'exécuter pendant assez longtemps pour que je remarque la fuite.

128
demandé sur Community 2008-09-02 21:37:12

9 réponses

j'utilise l'approche suivante pour trouver des fuites de mémoire en Java. J'ai utilisé jProfiler avec beaucoup de succès, mais je crois que n'importe quel outil spécialisé avec des capacités de graphage (les diffs sont plus faciles à analyser sous forme graphique) fonctionnera.

  1. démarrez l'application et attendez qu'elle atteigne l'état" stable", lorsque toute l'initialisation est terminée et que l'application est inactive.
  2. Exécuter l'opération suspectée de produire une fuite de mémoire plusieurs les temps pour permettre à n'importe quel cache, l'initialisation liée à DB d'avoir lieu.
  3. Lancez GC et prenez un snapshot mémoire.
  4. relancez l'opération. En fonction de la complexité de l'opération et de la taille des données traitées, l'opération peut devoir être exécutée plusieurs ou plusieurs fois.
  5. Lancez GC et prenez un snapshot mémoire.
  6. lancer une diff pour 2 instantanés et l'analyser.

essentiellement analyse devrait commencer à partir de la plus grande différence positive par, disons, les types d'objet et de trouver ce qui provoque ces objets supplémentaires à coller dans la mémoire.

pour les applications web qui traitent des requêtes dans plusieurs threads l'analyse devient plus compliquée, mais néanmoins l'approche générale s'applique toujours.

j'ai fait un certain nombre de projets spécifiquement visant à réduire l'empreinte mémoire des applications et cette approche générale avec quelques modifications spécifiques à l'application et astuce toujours bien fonctionné.

118
répondu Dima Malenko 2008-09-02 18:49:35

Questioner ici, je dois dire que l'obtention d'un outil qui ne prend pas 5 minutes pour répondre à chaque clic rend beaucoup plus facile de trouver des fuites de mémoire potentielles.

puisque les gens suggèrent plusieurs outils (Je n'ai essayé visual wm que depuis que je l'ai eu dans le JDK et JProbe trial ) je pense que je devrais suggérer un outil libre / open source construit sur la plate-forme Eclipse, L'Analyseur de mémoire (parfois référencé comme l'analyseur de mémoire SAP) disponible sur http://www.eclipse.org/mat / .

ce qui est vraiment cool au sujet de cet outil est qu'il indexé la décharge tas quand je l'ai ouvert pour la première fois qui lui a permis de montrer des données comme le tas retenu sans attendre 5 minutes pour chaque objet (à peu près toutes les opérations étaient des tonnes plus rapide que les autres outils que j'ai essayé).

lorsque vous ouvrez la benne, le premier écran vous montre un diagramme à secteurs avec les plus gros objets (en comptant le tas retenu) et on peut naviguer rapidement vers le bas pour les objets qui sont de grand confort. Il a également un Trouver des suspects de fuite probable que je reccon peut venir à portée de main, mais comme la navigation était suffisante pour moi, je n'ai pas vraiment entrer dans elle.

47
répondu jwiklund 2015-09-11 17:17:07

un outil est une grande aide.

cependant, il y a des moments où vous ne pouvez pas utiliser un outil: le tas dump est tellement énorme qu'il plante l'outil, vous essayez de dépanner une machine dans un environnement de production auquel vous n'avez accès qu'à l'interpréteur de commandes, etc.

dans ce cas, il est utile de connaître votre chemin dans le fichier dump hprof.

rechercher des SITES commencer. Cela vous montre quels objets utilisent le plus de mémoire. Mais les objets ne sont pas regroupé uniquement par type: chaque entrée comprend également un ID "trace". Vous pouvez alors rechercher Cette "TRACE nnnn" pour voir les quelques cadres supérieurs de la pile où l'objet a été alloué. Souvent, une fois que je vois où l'objet est alloué, je trouve un bug et j'en ai fini. Notez également que vous pouvez contrôler le nombre d'images enregistrées dans la pile avec les options à Xrunhprof.

si vous consultez le site d'allocation, et ne voyez rien de mal, vous devez commencer à enchaîner en arrière de certains de ces objets vivants à des objets racine, pour trouver la chaîne de référence inattendue. C'est là un outil qui aide vraiment, mais vous pouvez faire la même chose en main (bien, avec grep). Il n'y a pas qu'un seul objet racine (c.-à-d. un objet qui n'est pas assujetti à la collecte des ordures). Les fils, les classes et les cadres de pile agissent comme des objets racine, et tout ce qu'ils mentionnent fortement n'est pas collectible.

pour faire le chaînage, regardez dans la section tas DUMP pour les entrées avec le mauvais ID de trace. Ce vous mènera à une entrée OBJ ou ARR, qui montre un identifiant d'objet unique en hexadécimal. Cherchez toutes les occurrences de cette id pour trouver qui a une forte référence à l'objet. Suivez chacun de ces chemins vers l'arrière pendant qu'ils se ramifient jusqu'à ce que vous trouvez où la fuite est. Vous voyez pourquoi un outil est si pratique?

les membres Statiques sont un récidiviste de fuites de mémoire. En fait, même sans outil, il vaudrait la peine de passer quelques minutes à chercher à travers votre code pour la carte statique membre. Peut une carte de développer de grandes? Ne jamais nettoyer ses entrées?

12
répondu erickson 2008-09-02 18:30:42

la plupart du temps, dans les applications d'entreprise le tas de Java donné est plus grand que la taille idéale de max 12 à 16 Go. J'ai eu du mal à faire fonctionner le profileur NetBeans directement sur ces grandes applications java.

Mais ce n'est généralement pas nécessaire. Vous pouvez utiliser l'utilitaire jmap qui est fourni avec le jdk pour faire un "live" tas dump , c'est-à-dire que jmap va vider le tas après avoir lancé GC. Faire une opération sur l'application, attendre jusqu'à ce que l'opération est terminée, puis prendre image. Vous pouvez vider un histogramme de classe en direct avec l'outil jmap. Cela donnera seulement l'histogramme de classe de l'usage de mémoire.En gros, il n'aura pas l'information pour enchaîner la référence. Par exemple, il peut mettre le tableau de char au sommet. Et classe String quelque part en dessous. Vous devez établir le lien vous-même.

jdk/jdk1.6.0_38/bin/jmap -histo:live 60030 > /tmp/60030istolive1330.txt

au lieu de faire deux bonds en tas, prenez deux histogrammes de classe, comme décrit ci-dessus; puis comparez les histogrammes de classe et voyez les classes qui sont croissant. Voyez si vous pouvez relier les classes Java à vos classes d'application. Cela vous donnera une assez bonne idée de la. Voici un script pythons qui peut vous aider à comparer deux dumps d'histogrammes jmap. histogramparser.py

enfin des outils comme Jconolse et VisualVm sont essentiels pour voir la croissance de la mémoire dans le temps, et voir s'il y a une fuite de mémoire. Enfin parfois, votre problème ne peut pas être une fuite de mémoire , mais l'utilisation de mémoire.Pour cela, activer GC logging; utiliser un plus avancé et nouveau GC compacting comme G1GC; et vous pouvez utiliser des outils jdk comme jstat pour voir le comportement GC en direct

jstat -gccause pid <optional time interval>

autres références à google for-jhat, jmap, Full GC, Humongous allocation, G1GC

7
répondu Alex Punnen 2015-10-02 08:47:59

il y a des outils qui devraient vous aider à trouver votre fuite, comme JProbe, YourKit, AD4J ou JRockit Mission Control. Le dernier est celui que je connais le mieux. Tout bon outil devrait vous laisser creuser jusqu'à un niveau où vous pouvez facilement identifier les fuites, et où les objets qui fuient sont alloués.

utiliser HashTables, Hashmaps ou similaire est l'un des rares moyens que vous pouvez acually fuite de mémoire dans Java à tous. Si je devais trouver la fuite en main, je ne serait peridically Imprimer la taille de mes HashMaps, et de là trouver celui où je ajoute des éléments et oublier de les supprimer.

5
répondu Tnilsson 2008-09-02 17:48:30

Eh bien, il y a toujours la solution de basse technologie d'ajouter l'enregistrement de la taille de vos cartes quand vous les modifiez, puis rechercher les journaux pour lesquels les cartes sont en croissance au-delà d'une taille raisonnable.

4
répondu Mike Stone 2008-09-02 17:39:50

vous avez vraiment besoin d'utiliser un profileur de mémoire qui suit les allocations. Jetez un oeil à JProfiler - leur fonction "heap walker" est grande, et ils ont une intégration avec tous les principaux IDEs Java. Ce n'est pas gratuit, mais ce n'est pas si cher non plus (499$pour une seule licence) - vous brûlerez 500 $de temps assez rapidement luttant pour trouver une fuite avec des outils moins sophistiqués.

0
répondu McKenzieG1 2008-09-02 17:46:46

NetBeans a un profileur intégré.

0
répondu wbkang 2008-09-02 18:30:34

vous pouvez choisir de consulter jconsole . Il fait également partie du JDK et j'ai trouvé utile de trouver des fuites de mémoire/référence en conjonction avec le jhat. Jetez également un oeil à cette entrée de blog.

-1
répondu JMM 2008-09-02 18:39:08