Comment trouver une fuite de mémoire Java


Comment trouvez-vous une fuite de mémoire en Java (en utilisant, par exemple, JHat)? J'ai essayé de charger la décharge de tas dans JHat pour jeter un regard de base. Cependant, je ne comprends pas comment je suis censé être capable de trouver la référence racine (ref) ou tout ce qu'elle est appelée. Fondamentalement, je peux dire qu'il y a plusieurs centaines de mégaoctets d'entrées de table de hachage ([java.util.HashMap Entry Entry ou quelque chose comme ça), mais les cartes sont utilisées partout... Existe-t-il un moyen de rechercher de grandes cartes, ou peut-être trouver des racines générales de grands arbres d'objets?

[Modifier] Ok, j'ai lu les réponses jusqu'à présent mais disons simplement 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 car il fait partie du JDK. À moins bien sûr qu'il n'y ait aucun moyen avec JHat mais la force brute, mais je ne peux pas croire que cela puisse être le cas.

De plus, je ne pense pas pouvoir réellement modifier (en ajoutant la journalisation de toutes les tailles de carte) et le courir assez longtemps pour que je remarque la fuite.

Author: Community, 2008-09-02

9 answers

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 tout outil spécialisé avec des capacités graphiques (les différences 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écutez l'opération suspectée de produire une fuite de mémoire plusieurs fois pour autoriser tout cache, lié à la base de données initialisation à avoir lieu.
  3. Exécutez GC et prenez un instantané de mémoire.
  4. Exécutez à nouveau 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 à plusieurs fois.
  5. Exécutez GC et prenez un instantané de mémoire.
  6. Exécutez un diff pour 2 instantanés et analysez-le.

Fondamentalement, l'analyse devrait commencer à partir du plus grand diff positif par, disons, les types d'objets et trouver ce qui fait que ces objets supplémentaires restent 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 visant spécifiquement à réduire l'empreinte mémoire des applications et cette approche générale avec quelques ajustements et astuces spécifiques à l'application a toujours bien fonctionné.

 118
Author: Dima Malenko, 2008-09-02 18:49:35

Interlocuteur ici, je dois dire que l'obtention d'un outil qui ne prend pas 5 minutes pour répondre à un clic facilite beaucoup la recherche de fuites de mémoire potentielles.

Puisque les gens suggèrent plusieurs outils (je n'ai essayé que visual wm depuis que je l'ai obtenu dans l'essai JDK et JProbe), je devrais suggérer un outil gratuit / 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 avec cet outil, c'est qu'il a indexé le vidage du tas lorsque je l'ai ouvert pour la première fois, ce qui lui a permis d'afficher des données comme le tas conservé sans attendre 5 minutes pour chaque objet (à peu près toutes les opérations étaient des tonnes plus rapides que les autres outils

Lorsque vous ouvrez le vidage, le premier écran vous montre un camembert avec les objets les plus gros (en comptant le tas conservé) et on peut rapidement naviguer vers les objets qui sont trop grands pour le confort. Il a également une découverte probable les suspects de fuite que je reccon peuvent être utiles, mais comme la navigation me suffisait, je ne m'y suis pas vraiment mis.

 47
Author: jwiklund, 2015-09-11 17:17:07

Un outil est d'une grande aide.

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

Dans ce cas, il est utile de connaître votre chemin autour du fichier de vidage hprof.

Rechercher des SITES COMMENCE. Cela vous montre quels objets utilisent le plus de mémoire. Mais les objets ne sont pas regroupés uniquement par type: chaque entrée comprend également un IDENTIFIANT "trace". Vous pouvez ensuite rechercher cette "TRACE nnnn" pour voir les quelques premières images de la pile où l'objet a été alloué. Souvent, une fois que je vois où l'objet est alloué, je trouve un bogue et j'ai terminé. 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 que vous ne voyez rien de mal, vous devez commencer à enchaîner en arrière de certains de ces objets vivants aux objets racine, pour trouver l'inattendu chaîne de référence. C'est là qu'un outil aide vraiment, mais vous pouvez faire la même chose à la main (enfin, avec grep). Il n'y a pas qu'un seul objet racine (c'est-à-dire un objet non soumis à la récupération de place). Les threads, les classes et les cadres de pile agissent comme des objets racine, et tout ce qu'ils référencent fortement n'est pas à collectionner.

Pour effectuer le chaînage, recherchez dans la section de VIDAGE de tas les entrées avec le mauvais id de trace. Cela vous amènera à une entrée OBJ ou ARR, qui affiche un identifiant d'objet unique dans hexadécimal. Recherchez toutes les occurrences de cet id pour trouver qui a une référence forte à l'objet. Suivez chacun de ces chemins vers l'arrière pendant qu'ils se ramifient jusqu'à ce que vous compreniez où se trouve la fuite. Voyez pourquoi un outil est si pratique?

Les membres statiques sont des récidivistes pour les fuites de mémoire. En fait, même sans outil, il vaudrait la peine de passer quelques minutes à parcourir votre code pour trouver des membres de carte statiques. Peut une carte de développer de grandes? Ne jamais nettoyer ses entrées?

 12
Author: erickson, 2008-09-02 18:30:42

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

Mais généralement ce n'est pas nécessaire. Vous pouvez utiliser l'utilitaire jmap fourni avec le jdk pour effectuer un vidage de tas "en direct", c'est-à-dire que jmap videra le tas après avoir exécuté GC. Faites une opération sur l'application, attendez que l'opération soit terminée, puis prenez un autre vidage de tas "live". Utilisez des outils comme Eclipse MAT pour charger les tasdumps, trier sur l'histogramme, voir quels objets ont augmenté ou quels sont les plus élevés, Cela donnerait un indice.

su  proceeuser
/bin/jmap -dump:live,format=b,file=/tmp/2930javaheap.hrpof 2930(pid of process)

Il n'y a qu'un seul problème avec cette approche; D'énormes décharges de tas, même avec l'option live, peuvent être trop grandes pour être transférées vers le tour de développement, et peuvent avoir besoin d'une machine avec suffisamment de mémoire/RAM pour s'ouvrir.

C'est là que l'histogramme de classe entre en image. Vous pouvez vider un histogramme de classe en direct avec l'outil jmap. Ce ne donnera que l'histogramme de classe de l'utilisation de la mémoire.Fondamentalement, il n'aura pas les informations pour enchaîner la référence. Par exemple, il peut mettre un tableau de caractères en haut. Et la classe String quelque part en dessous. Vous devez établir la connexion vous-même.

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

Au lieu de prendre deux décharges de tas, prenez deux histogrammes de classe, comme décrit ci-dessus; Puis comparez les histogrammes de classe et voyez les classes qui augmentent. Voyez si vous pouvez relier les classes Java à vos classes d'application. Ce sera donner une assez bonne idée de la. Voici un script pythons qui peut vous aider à comparer deux vidages d'histogrammes jmap. histogramparser.py

Enfin, des outils comme JConolse et VisualVM sont essentiels pour voir la croissance de la mémoire au fil du 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, activez la journalisation du GC; utilisez un GC de compactage plus avancé et nouveau comme G1GC; et vous pouvez utiliser des outils jdk comme jstat pour voir le comportement du GC vivre

jstat -gccause pid <optional time interval>

Autres références à google pour-jhat, jmap, Full GC, Humongous allocation, G1GC

 7
Author: Alex Punnen, 2015-10-02 08:47:59

Il existe 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 permettre de descendre à un niveau où vous pouvez facilement identifier les fuites et où les objets qui fuient sont alloués.

L'utilisation de HashTables, Hashmaps ou similaires est l'une des rares façons de fuir de la mémoire en Java. Si je devais trouver la fuite à la main j'imprimerais péridiquement la taille de mon HashMaps, et à partir de là trouver celui où j'ajoute des éléments et oublie de les supprimer.

 5
Author: Tnilsson, 2008-09-02 17:48:30

Eh bien, il y a toujours la solution low tech d'ajouter la journalisation de la taille de vos cartes lorsque vous les modifiez, puis recherchez les journaux pour lesquels les cartes dépassent une taille raisonnable.

 4
Author: Mike Stone, 2008-09-02 17:39:50

Vous devez vraiment utiliser un profileur de mémoire qui suit les allocations. Jetez un oeil à JProfiler - leur fonctionnalité "heap walker" est géniale, et ils ont une intégration avec tous les principauxEs Java. Ce n'est pas gratuit, mais ce n'est pas si cher non plus (499 for pour une seule licence) - vous brûlerez 500 worth de temps assez rapidement pour trouver une fuite avec des outils moins sophistiqués.

 0
Author: McKenzieG1, 2008-09-02 17:46:46

NetBeans a un profileur intégré.

 0
Author: wbkang, 2008-09-02 18:30:34

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

 -1
Author: JMM, 2008-09-02 18:39:08