2012-04-11 5 views
26

Je suis encore en train d'apprendre les ficelles du Java si désolé si il y a une réponse évidente à cela. J'ai un programme qui prend beaucoup de mémoire et je veux trouver un moyen de réduire son utilisation, mais après avoir lu beaucoup de questions, j'ai l'idée que je dois prouver où est le problème avant de commencer à l'optimiser. Donc voici ce que j'ai fait, j'ai ajouté un point de rupture au début de mon programme et l'ai exécuté, puis j'ai lancé visualVM et l'ai profilé la mémoire (j'ai aussi fait la même chose dans netbeans juste pour comparer les résultats et ce sont les mêmes). Mon problème est que je ne sais pas comment les lire, j'ai la zone la plus haute juste en disant char[] et je ne peux pas voir de code ou quoi que ce soit (ce qui est logique car visualvm se connecte au jvm et ne peut pas voir ma source, mais netbeans ne me montre pas non plus la source comme c'est le cas pour le profilage de cpu). Fondamentalement ce que je veux savoir est quelle variable (et j'espère plus de détails comme dans quelle méthode) toute la mémoire est utilisée afin que je puisse me concentrer sur travailler là. Y a-t-il un moyen facile de faire cela? En ce moment, j'utilise eclipse et java pour développer (et installé visualVM et netbeans spécifiquement pour le profilage, mais je suis prêt à installer tout ce qui, selon moi, fait ce travail).Comment profil de mémoire en Java?

EDIT: Idéalement, je cherche quelque chose qui va prendre tous mes objets et les trier par taille (afin que je puisse voir lequel est la mémoire monopolisant). Actuellement, il renvoie des informations génériques telles que string [] ou int [] mais je veux savoir à quel objet il fait référence afin de pouvoir optimiser sa taille.

+0

J'utilise un profileur qui me montre également où les objets sont alloués. Je ne sais pas si VisualVM peut le faire, mais c'est très utile. Celui que j'utilise est YourKit, mais ce n'est pas gratuit (mais vous pouvez obtenir une licence eval) –

+0

@PeterLawrey J'ai effectivement lu une réponse que vous avez écrite il y a quelque temps où vous avez mentionné que yourkit était votre premier choix, je l'ai cherché (car votre conseil est toujours génial) mais oui c'est un peu cher et je suis en train d'apprendre. –

+0

sans utiliser quelque chose qui instrumente votre code, aucun analyseur ne sera capable de montrer quelle instance == ce que vous appelez une référence dans votre source. –

Répondre

22

cordes sont problématiques

Fondamentalement en Java, String références (choses qui utilisent char[] dans les coulisses) dominera la plupart entreprises applications mémoire sage. La manière 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 professionnelles en tant que type de données, et qu'ils sont également les plus gourmands en mémoire. Ce n'est pas seulement une chose Java, String les types de données occupent beaucoup de mémoire dans à peu près toutes les bibliothèques de langue et d'exécution, car au moins ils sont juste des tableaux de 1 octet par caractère ou pire (Unicode) ils sont des tableaux de plusieurs octets par caractère.

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

Qu'est-ce que vous êtes préoccupé par vous ne pouvez pas contrôler, non pas directement de toute façon

Ce que vous devez vous concentrer sur ce qui est dans votre contrôle, ce qui fait que vous ne tenez pas à des références plus que vous devez, et que vous ne dupliquez pas les choses inutilement. Les routines de récupération de place Java sont hautement optimisées, et si vous apprenez comment leurs algorithmes fonctionnent, vous pouvez vous assurer que votre programme se comporte de manière optimale pour que ces algorithmes fonctionnent.

Java Heap mémoire est pas comme mémoire gérée manuellement dans d'autres langues, ces règles ne sont pas applicables

Qu'est-ce que sont considérés comme des fuites de mémoire dans d'autres langues ne sont pas la même chose/cause racine en Java avec son système de collecte des ordures.

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

Il est beaucoup plus probable des allocations plus petites en raison de StringBuffer/objets StringBuilder pas de taille appropriée, sur les premières instantantations et ayant à croître automatiquement les tableaux char[] pour tenir append() ultérieures appels.

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

Exemple: le collecteur d'ordures peut décider qu'il ya des candidats, mais parce qu'il estime qu'il y a beaucoup de mémoire encore être fait qu'il pourrait être temps trop cher sage de les débusquer à ce moment, 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 façon optimale. Il y a beaucoup de documentation sur Internet à propos des paramètres de garbage collector pour toutes les versions des JVM.

Ces objets non référencés n'ont peut-être pas atteint l'heure à laquelle le ramasse-miettes pense qu'ils en ont besoin pour être effacés de la mémoire, ou il pourrait y avoir des références à un autre objet (List) par exemple que vous ne réalisez pas encore de points sur cet objet. C'est ce que l'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 construire un 4K String en utilisant un StringBuilder créer avec new StringBuilder(4096); pas la valeur par défaut, ce qui est comme 32 et immédiatement commencer à créer des déchets qui peuvent représenter plusieurs fois ce que vous pensez que l'objet devrait être taille sage.

Vous pouvez découvrir combien de types d'objets sont instanciés avec VisualVM, cela vous dira ce que vous devez savoir. Il n'y aura pas un seul gros clignotant qui pointe vers une seule instance d'une seule classe qui dit: «C'est le grand consommateur de mémoire!», À moins qu'il n'y ait qu'une seule instance de certains char[] que vous lisez un fichier massif dans, et ce n'est pas possible non plus, car beaucoup d'autres classes utilisent char[] en interne; et alors vous le saviez déjà.

Je ne vois aucune mention de OutOfMemoryError

Vous n'avez probablement pas un problème dans votre code, le système de collecte des ordures pourrait bien ne pas être de se mettre sous une pression suffisante pour lancer et objets désaffecter que vous pense il devrait être de nettoyage. Quel vous pensez que est probablement pas un problème, non à moins que votre programme plante avec OutOfMemoryError.Ce n'est pas C, C++, Objective-C, ou tout autre langage de gestion de mémoire manuelle/runtime. Vous ne pouvez pas décider ce qui est en mémoire ou non au niveau de détail auquel vous vous attendez.

0

Si vous utilisez visualVM pour vérifier votre utilisation de la mémoire, il se concentre sur les données et non sur les méthodes. Peut-être que vos grandes données char [] sont causées par de nombreuses valeurs de chaîne? À moins que vous n'utilisiez 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 en savoir quelles déclarations précises cause de votre « fuite de mémoire », je vous suggère de plus

2

Je vous recommande de capturer des décharges de tas et d'utiliser un outil comme Eclipse MAT qui vous permet de les analyser. Il y a beaucoup de tutorials disponibles. Il fournit une vue du dominator tree pour fournir un aperçu des relations entre les objets sur le tas. Spécifiquement pour ce que vous avez mentionné, la fonction "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 pour identifier les fuites et les allocations, en particulier en utilisant des snapshots avec des traces de pile d'allocation. Il y a quelques walk-throughs of the process d'obtenir les instantanés et de les comparer pour trouver le point d'allocation.

7

Dans JProfiler, vous pouvez accéder au segment de mémoire et activer la vue des objets les plus volumineux. Vous verrez les objets les plus mémorisés. La mémoire "Retained" est la mémoire qui serait libérée par le garbage collector si vous supprimiez l'objet.

Vous pouvez ensuite ouvrir les noeuds 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:

enter image description here

Avertissement: Mon entreprise se développe JProfiler

1

Java JDK est livré avec jVisualVM sous 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 ordinateur local, qui fournira vous l'allocation de mémoire et vous permettre d'effectuer tas décharge

enter image description here

Pour plus de détails sur la procédure d'activation: http://sysdotoutdotprint.com/index.php/2017/08/01/turn-profiler-java/

Questions connexes