Comment faire un profil de mémoire en Java?


J'apprends toujours les cordes de Java, donc désolé s'il y a une réponse évidente à cela. J'ai un programme qui prend une tonne de mémoire et je veux trouver un moyen de réduire son utilisation, mais après avoir lu de nombreuses questions SO, j'ai l'idée que je dois prouver où est le problème avant de commencer à l'optimiser.

Voici donc ce que j'ai fait, j'ai ajouté un point d'arrêt au début de mon programme et je l'ai exécuté, puis j'ai commencé VisualVM et je l'ai fait profiler la mémoire (j'ai aussi fait la même chose dans netbeans juste pour comparer les résultats et ils sont les mêmes). Mon problème est que je ne sais pas comment les lire, j'ai la zone la plus élevée en disant simplement char[] et je ne vois aucun code ou quoi que ce soit(ce qui est logique car visualvm se connecte à la jvm et ne peut pas voir ma source, mais netbeans ne me montre pas non plus la source comme

Fondamentalement, ce que je veux savoir, c'est quelle variable (et j'espère plus de détails comme dans quelle méthode) toute la mémoire est utilisée pour que je puisse me concentrer d'y travailler. Est-il un moyen facile de faire cela? En ce moment, j'utilise eclipse et java pour développer (et j'ai installé VisualVM et netbeans spécifiquement pour le profilage, mais je suis prêt à installer tout ce qui vous semble faire ce travail).

EDIT: Idéalement, je cherche quelque chose qui prendra tous mes objets et les triera par taille(afin que je puisse voir lequel monopolise la mémoire). Actuellement, il renvoie des informations génériques telles que string [] ou int [] mais je veux savoir quel objet son se référant à afin que je puisse travailler à obtenir sa taille plus optimisée.

Author: Error_404, 2012-04-11

5 answers

Les Chaînes sont problématiques

Fondamentalement en Java, les références String (choses qui utilisent char[] dans les coulisses ) domineront la plupart des applications business en termes de mémoire. La façon dont ils sont créés détermine la quantité de mémoire qu'ils consomment dans la JVM.

Tout simplement parce qu'ils sont si fondamentaux pour la plupart des applications métier en tant que type de données, et qu'ils sont également l'un des plus gourmands en mémoire. Ce n'est pas seulement une chose Java, les types de données String prennent beaucoup de mémoire dans à peu près toutes les bibliothèques de langues et d'exécution, car au moins ce ne sont que des tableaux de 1 octet par caractère ou au pire ( Unicode), ce sont des tableaux de plusieurs octets par caractère.

Une fois, lors du profilage de l'utilisation du PROCESSEUR sur une application Web qui avait également une dépendance Oracle JDBC, j'ai découvert que StringBuffer.append()dominait les cycles du PROCESSEUR de plusieurs ordres de grandeur par rapport à tous les autres appels de méthode combinés, encore moins tout autre appel de méthode unique. Le pilote JDBC a fait beaucoup, beaucoup de String manipulation, sorte de compromis d'utiliser PreparedStatements pour tout.

Ce qui vous préoccupe, vous ne pouvez pas le contrôler, pas directement de toute façon

Ce sur quoi vous devriez vous concentrer, c'est ce que vous contrôlez, c'est-à-dire vous assurer que vous ne conservez pas les références plus longtemps que nécessaire, et que vous ne dupliquez pas les choses inutilement. Les routines de garbage collection en Java sont hautement optimisées, et si vous apprenez comment leurs algorithmes fonctionnent, vous pouvez vous assurer que votre programme se comporte de la manière optimale pour que ces algorithmes fonctionnent.

La mémoire de tas Java n'est pas comme la mémoire gérée manuellement dans d'autres langages, ces règles ne s'appliquent pas

Ce qui est considéré comme les fuites de mémoire dans d'autres langages ne sont pas la même chose/cause racine qu'en Java avec son système de récupération de place.

Très probablement, la mémoire Java n'est pas consommée par un seul objet uber qui fuit ( référence pendante dans d'autres environnements ).

C'est très probablement beaucoup de petites allocations en raison de StringBuffer/StringBuilder les objets ne sont pas dimensionnés de manière appropriée lors des premières instantanations et doivent ensuite développer automatiquement les tableaux char[] pour contenir les appels append() suivants.

Ces objets intermédiaires peuvent être détenus plus longtemps que prévu par le garbage collector en raison de la portée et de beaucoup d'autres choses qui peuvent varier au moment de l'exécution.

EXEMPLE: {[20] } le garbage collector peut décider qu'il y a des candidats, mais parce qu'il considère qu'il y a encore beaucoup de mémoire à avoir, il pourrait être trop coûteux de les vider à ce moment-là, et il attendra jusqu'à ce que la pression de la mémoire augmente.

Le garbage collector est vraiment bon maintenant, mais ce n'est pas magique, si vous faites des choses dégénérées, cela ne fonctionnera pas de manière optimale. Il y a beaucoup de documentation sur Internet sur les paramètres du garbage collector pour toutes les versions des JVM.

Ces les objets non référencés peuvent simplement ne pas avoir atteint le moment où le garbage collector pense qu'il en a besoin pour qu'ils soient effacés de la mémoire, ou il peut y avoir des références à eux détenues par un autre objet ( List ) par exemple que vous ne réalisez pas encore des points vers cet objet. C'est ce qu'on appelle le plus souvent une fuite en Java, qui est une fuite de référence plus spécifiquement.

EXEMPLE: Si vous savez que vous devez créer un 4K String en utilisant un StringBuilder create avec new StringBuilder(4096); pas la valeur par défaut, qui est comme 32 et commencera immédiatement à créer des ordures qui peuvent représenter plusieurs fois ce que vous pensez que l'objet devrait être de taille.

Vous pouvez découvrir combien de quels types d'objets sont instanciés avec VisualVM, cela vous dira ce que vous devez savoir. Il ne va pas y avoir une grande lumière clignotante qui pointe vers une seule instance d'une seule classe qui dit: "C'est le grand consommateur de mémoire!", c'est-à moins qu'il n'existe qu'une seule instance de certains char[] dans lesquels vous lisez un fichier massif, et ce n'est pas possible non plus, car beaucoup d'autres classes utilisent char[] en interne; et puis vous le saviez déjà à peu près.

Je ne vois aucune mention de OutOfMemoryError

Vous n'avez probablement pas de problème dans votre code, le système de récupération de place pourrait ne pas être mis suffisamment sous pression pour lancer et désallouer des objets que vous pensez il devrait nettoyer. Quoi vous pensez que est un problème qui ne l'est probablement pas, à moins que votre programme ne plante avec OutOfMemoryError. Ce n'est pas C, C++, Objective-C ou tout autre langage / runtime de gestion manuelle de la mémoire. Vous ne pouvez pas décider ce qui est en mémoire ou non au niveau de détail que vous attendez que vous devriez pouvoir.

 24
Author: feeling abused and harassed, 2012-04-11 16:52:16

Dans JProfiler, vous pouvez aller au marcheur de tas et activer la vue des objets les plus grands. Vous verrez les objets qui conservent le plus de mémoire. La mémoire "conservée" est la mémoire qui serait libérée par le garbage collector si vous supprimiez l'objet.

Vous pouvez ensuite ouvrir les nœuds d'objet pour voir l'arborescence de référence des objets conservés. Voici une capture d'écran de la plus grande vue d'objet:

entrez la description de l'image ici

Avertissement: Mon entreprise développe JProfiler

 8
Author: Ingo Kegel, 2012-04-15 14:54:49

Je recommanderais de capturer des décharges de tas et d'utiliser un outil comme Eclipse MAT qui vous permet de les analyser. Il existe de nombreuxtutoriels disponibles. Il fournit une vue de l'arbredominator pour fournir un aperçu des relations entre les objets sur le tas. Plus précisément pour ce que vous avez mentionné, la fonctionnalité "chemin vers les racines GC" de MAT vous dira où la majorité de ces objets char[], String[] et int[] sont référencés. JVisualVM peut également être utile dans identifier les fuites et les allocations, en particulier en utilisant des instantanés avec des traces de pile d'allocation. Il y a pas mal de étapes du processus d'obtention des instantanés et de comparaison pour trouver le point d'allocation.

 2
Author: Rob Tanzola, 2012-04-12 00:43:02

Java JDK est livré avec JVisualVM sous le dossier bin, une fois que votre serveur d'applications (par exemple est en cours d'exécution), vous pouvez exécuter visualvm et le connecter à votre localhost, ce qui vous fournira une allocation de mémoire et vous permettra d'effectuer un vidage de tas

entrez la description de l'image ici

Pour des étapes plus détaillées sur la façon d'activer: http://sysdotoutdotprint.com/technologies/java/6

 2
Author: mel3kings, 2018-04-04 05:18:23

Si vous utilisez VisualVM pour vérifier votre utilisation de la mémoire, il se concentre sur les données, pas sur les méthodes. Peut-être que vos données big char[] sont causées par de nombreuses valeurs de chaîne? Sauf si vous utilisez la récursivité, les données ne proviendront pas de variables locales. Vous pouvez donc vous concentrer sur les méthodes qui insèrent des éléments dans de grandes structures de données. Pour savoir quelles déclarations précises provoquent votre "fuite de mémoire", je vous suggère en outre

 0
Author: DaveFar, 2012-04-11 15:32:48