Comment trouvez-vous une fuite de mémoire en Java (en utilisant, par exemple, JHat)? J'ai essayé de charger le vidage de tas dans JHat pour jeter un coup d'œil de base. Cependant, je ne comprends pas comment je suis censé pouvoir trouver la référence racine ( ref ) ou quel que soit son nom. Fondamentalement, je peux dire qu'il existe plusieurs centaines de mégaoctets d'entrées de table de hachage ([java.util.HashMap $ Entry ou quelque chose comme ça), mais les cartes sont utilisées partout ... Y a-t-il un moyen de rechercher de grandes cartes , ou peut-être trouver des racines générales de grands arbres d'objets?
[Edit] Ok, j'ai lu les réponses jusqu'à présent, mais disons simplement que je suis un salaud bon marché (ce qui signifie que je suis plus intéressé à apprendre à utiliser JHat qu'à payer 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 que je pourrai réellement modifier (en ajoutant la journalisation de toutes les tailles de carte) et l'exécuter assez longtemps pour que je remarque la fuite.
la source
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 pense que tout outil spécialisé avec des capacités graphiques (les différences sont plus faciles à analyser sous forme graphique) fonctionnera.
Fondamentalement, l'analyse doit commencer à partir de la plus grande différence positive par, par exemple, des types d'objets et trouver ce qui fait que ces objets supplémentaires restent en mémoire.
Pour les applications Web qui traitent les requêtes dans plusieurs threads, l'analyse devient plus compliquée, mais l'approche générale s'applique néanmoins.
J'ai réalisé 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é.
la source
Interlocuteur ici, je dois dire que l'obtention d'un outil qui ne prend pas 5 minutes pour répondre à n'importe quel clic facilite beaucoup la recherche de fuites de mémoire potentielles.
Étant donné que les gens suggèrent plusieurs outils (j'ai seulement essayé visual wm depuis que je l'ai eu dans l'essai JDK et JProbe), je pense que je devrais suggérer un outil gratuit / open source construit sur la plate-forme Eclipse, l'analyseur de mémoire (parfois appelé mémoire SAP analyseur) disponible sur http://www.eclipse.org/mat/ .
Ce qui est vraiment cool à propos de 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 beaucoup plus rapides que les autres outils que j'ai essayés) .
Lorsque vous ouvrez la décharge, le premier écran vous montre un diagramme à secteurs avec les plus gros objets (en comptant le tas conservé) et on peut rapidement naviguer vers les objets qui sont trop gros pour le confort. Il a également une recherche de suspects de fuite probable que je reconnais peut être utile, mais comme la navigation était suffisante pour moi, je n'y suis pas vraiment entré.
la source
HeapDumpOnCtrlBreak
paramètre VM n'est pas disponible . La solution que j'ai trouvée (jusqu'à présent, toujours à la recherche) est d'utiliser JMap pour vider le.hprof
fichier, que je place ensuite dans Eclipse et que j'utilise MAT pour l'examiner.Un outil est d'une grande aide.
Cependant, il y a des moments où vous ne pouvez pas utiliser un outil: le vidage du tas est si é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 dans le fichier de vidage hprof.
Recherchez SITES BEGIN. 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 ID "trace". Vous pouvez ensuite rechercher ce "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'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 le chaînage arrière de certains de ces objets en direct vers des objets racine, pour trouver la chaîne de référence inattendue. 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 au garbage collection). Les threads, classes et cadres de pile agissent comme des objets racine, et tout ce qu'ils référencent fortement n'est pas collectable.
Pour effectuer le chaînage, recherchez dans la section HEAP DUMP les entrées avec l'ID de trace incorrect. Cela vous mènera à une entrée OBJ ou ARR, qui affiche un identifiant d'objet unique en hexadécimal. Recherchez toutes les occurrences de cet identifiant pour trouver qui a une référence forte à l'objet. Suivez chacun de ces chemins vers l'arrière pendant qu'ils se branchent jusqu'à ce que vous trouviez 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, cela vaudrait la peine de passer quelques minutes à rechercher dans votre code les membres statiques de la carte. Une carte peut-elle s'agrandir? Est-ce que quelque chose nettoie jamais ses entrées?
la source
jhat
et j'aiMAT
apparemment essayé de charger le vidage du tas entier en mémoire, et donc typiquement planter avec un vidage deOutOfMemoryError
grande taille (c'est-à-dire des applications qui avaient le plus besoin d'une analyse de tas! ). Le NetBeans Profiler semble utiliser un algorithme différent pour l'indexation des références, ce qui peut devenir lent sur les gros vidages mais au moins ne consomme pas de mémoire illimitée dans l'outil et plante.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 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 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. Effectuez une opération sur l'application, attendez que l'opération soit terminée, puis effectuez un autre vidage de tas "en direct". Utilisez des outils comme Eclipse MAT pour charger les tas de tas, trier sur l'histogramme, voir quels objets ont augmenté, ou lesquels sont les plus élevés, cela donnerait un indice.
Il n'y a qu'un seul problème avec cette approche; D'énormes vidages de tas, même avec l'option live, peuvent être trop volumineux pour être transférés vers le tour de développement, et peuvent nécessiter une machine avec suffisamment de mémoire / RAM pour s'ouvrir.
C'est là que l'histogramme de classe entre en scène. Vous pouvez vider un histogramme de classe en direct avec l'outil jmap. Cela 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 le lien vous-même.
Au lieu de prendre deux vidages de tas, prenez deux histogrammes de classe, comme décrit ci-dessus; Ensuite, comparez les histogrammes de classe et voyez les classes qui augmentent. Voyez si vous pouvez associer les classes Java à vos classes d'application. Cela donnera un assez bon indice. Voici un script pythons qui peut vous aider à comparer deux vidages d'histogramme 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 peut ne pas être une fuite de mémoire, mais une utilisation élevée de la mémoire. Pour cela, activez la journalisation 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 en direct
Autres références à google pour -jhat, jmap, Full GC, Humongous allocation, G1GC
la source
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 personnellement. 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'un des rares moyens de perdre réellement de la mémoire en Java. Si je devais trouver la fuite à la main, j'imprimerais péridiquement la taille de mes HashMaps, et à partir de là, je trouverais celui où j'ajoutais des éléments et j'oublierais de les supprimer.
la source
Eh bien, il y a toujours la solution de faible technologie d'ajouter une journalisation de la taille de vos cartes lorsque vous les modifiez, puis recherchez les journaux pour lesquels les cartes augmentent au-delà d'une taille raisonnable.
la source
NetBeans a un profileur intégré.
la source
Vous devez vraiment utiliser un profileur de mémoire qui suit les allocations. Jetez un oeil à JProfiler - leur fonctionnalité "heap walker" est excellente, et ils ont une intégration avec tous les principaux IDE 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 en luttant pour trouver une fuite avec des outils moins sophistiqués.
la source
Vous pouvez le savoir en mesurant la taille d'utilisation de la mémoire après avoir appelé plusieurs fois garbage collector:
Si les nombres de sortie étaient égaux, il n'y a pas de fuite de mémoire dans votre application, mais si vous constatez une différence entre les nombres d'utilisation de la mémoire (nombres croissants), il y a une fuite de mémoire dans votre projet. Par exemple:
Notez que parfois, il faut un certain temps pour libérer de la mémoire par certaines actions comme les flux et les sockets. Vous ne devez pas juger par les premières sorties, vous devez le tester dans un laps de temps spécifique.
la source
Consultez cet écran sur la recherche de fuites de mémoire avec JProfiler. C'est une explication visuelle de @Dima Malenko Answer.
Remarque: Bien que JProfiler ne soit pas un logiciel gratuit, la version d'essai peut gérer la situation actuelle.
la source
Comme la plupart d'entre nous utilisent déjà Eclipse pour écrire du code, pourquoi ne pas utiliser l'outil d'analyse de la mémoire (MAT) dans Eclipse. Cela fonctionne très bien.
L' Eclipse MAT est un ensemble de plug-ins pour Eclipse IDE qui offre des outils d'analyse
heap dumps
de l' application Java et d'identifiermemory problems
dans l'application.Cela aide le développeur à trouver des fuites de mémoire avec les fonctionnalités suivantes
la source