web-dev-qa-db-fra.com

Comment surveiller Java?

Nous avons une application j2ee s'exécutant sur Jboss et nous voulons surveiller son utilisation de la mémoire. Actuellement, nous utilisons le code suivant

    System.gc();
    Runtime rt = Runtime.getRuntime();
    long usedMB = (rt.totalMemory() - rt.freeMemory()) / 1024 / 1024;
    logger.information(this, "memory usage" + usedMB);

Ce code fonctionne bien. Cela signifie que la courbe de la mémoire correspond à la réalité. Lorsque nous créons un gros fichier xml à partir d'une base de données, la courbe augmente, une fois l'extraction terminée, elle diminue.

alt text

Un consultant nous a dit qu'appeler explicitement gc () était une erreur, "laissez jvm décider quand exécuter gc". Fondamentalement, ses arguments étaient les mêmes que expliqué ici . Mais je ne comprends toujours pas:

  • comment puis-je avoir ma courbe d'utilisation de la mémoire?
  • qu'est-ce qui ne va pas avec gc () explicite? Je me fiche de petits problèmes de performances pouvant survenir avec explicit gc () et que j'estimerais dans une proportion de 1 à 3%. Ce dont j'ai besoin, c’est la mémoire et le moniteur de fil, ce qui m’aide dans l’analyse de notre système sur le site du client.
58
Oleg Pavliv

Si vous voulez vraiment regarder ce qui se passe dans la mémoire VM, vous devriez utiliser un bon outil comme VisualVM . Ce logiciel est gratuit et c'est un excellent moyen de voir ce qui se passe.

Rien n’est vraiment "faux" avec les appels explicites de gc (). Cependant, rappelez-vous que lorsque vous appelez gc (), vous "suggérez" que le ramasse-miettes s'exécute. Il n'y a aucune garantie qu'il s'exécutera à l'heure exacte où vous exécutez cette commande.

51
amischiefr

Certains outils vous permettent de surveiller l'utilisation de la mémoire de la machine virtuelle. Le la VM peut exposer les statistiques de mémoire en utilisant JMX . Vous pouvez également imprimer les statistiques du GC pour voir l’évolution de la mémoire au fil du temps.

Invoquer System.gc () peut nuire aux performances du GC, car les objets seront déplacés prématurément des générations les plus anciennes aux anciennes générations, et les références faibles seront effacées prématurément. Cela peut entraîner une diminution de l'efficacité de la mémoire, des délais plus longs sur le GC et une diminution du nombre d'accès au cache (pour les caches utilisant des références faibles). Je suis d'accord avec votre consultant: System.gc () est mauvais. J'irais jusqu'à le désactiver en utilisant le commutateur de ligne de commande.

28

Vous pouvez jeter un oeil à stagemonitor . Il s'agit d'un analyseur de performances d'une application open source Java (Web). Il enregistre les métriques de temps de réponse, les métriques JVM, les détails de la demande (y compris une pile d'appels capturée par le profileur de demandes), etc. très lent.

Vous pouvez également utiliser le super graphite de base de données timeseries pour stocker une longue histoire de points de données que vous pouvez consulter avec des tableaux de bord sophistiqués.

Exemple: JVM Memory Dashboard

Jetez un coup d'œil au site Web du projet pour voir des captures d'écran, des descriptions de fonctions et de la documentation.

Note: Je suis le développeur de stagiaire

10
Felix

Je dirais que le consultant a raison dans la théorie et vous avez raison dans la pratique. Comme le en disant va :

En théorie, théorie et pratique sont les mêmes. En pratique, ils ne le sont pas.

La spécification Java indique que System.gc suggère d'appeler le ramasse-miettes. En pratique, il génère simplement un thread et s'exécute immédiatement sur la JVM de Sun.

Bien qu'en théorie, vous puissiez gâcher une implémentation de récupération de mémoire JVM parfaitement réglée, à moins d'écrire du code générique destiné à être déployé sur n'importe quelle JVM, ne vous inquiétez pas. Si cela fonctionne pour vous, faites-le.

9
Yishai
8
Tom

Découvrez ce qui se passe à l'intérieur de Tomcat via Visual VM. http://www.skill-guru.com/blog/2010/10/05/increasing-permgen-size-in-your-server/ alt text

alt text

6
vsingh

Exécuter explicitement System.gc () sur un système de production est une idée terrible. Si la mémoire atteint n'importe quelle taille, l'ensemble du système peut se figer pendant l'exécution d'un GC complet. Sur un serveur de plusieurs gigaoctets, cela peut facilement être perceptible, en fonction de la configuration du jvm, de sa marge de sécurité, etc. - J'ai vu des pauses de plus de 30 secondes.

Un autre problème est qu'en appelant explicitement le GC, vous ne surveillez pas réellement le fonctionnement de la JVM, mais vous le modifiez. En fonction de la configuration de la JVM, il est possible de le ramasser, s'il y a lieu, et généralement de manière incrémentielle. (Cela ne fait pas que lancer un GC complet quand il manque de mémoire). Ce que vous allez imprimer ne ressemblera en rien à ce que la machine virtuelle Java fera par elle-même - vous verrez probablement moins de GC automatiques/incrémentielles puisque vous effacerez la mémoire manuellement.

Comme le souligne l'article de Nick Holt, les options permettant d'imprimer l'activité du GC existent déjà sous forme d'indicateurs JVM.

Vous pourriez avoir un fil qui s'imprime gratuitement et disponible à des intervalles raisonnables, cela vous montrera la mémoire réelle.

5
Steve B.

Examinez les arguments de la machine virtuelle Java: http://Java.Sun.com/javase/technologies/hotspot/vmoptions.jsp#DebuggingOptions

XX: -PrintGC Imprime les messages lors de la récupération de place. Maniable.

-XX: -PrintGCDetails Imprimez plus de détails lors de la récupération de place. Maniable. (Introduit dans 1.4.0.)

-XX: -PrintGCTimeStamps Imprimer des horodatages lors du nettoyage de la mémoire. Gérable (Introduit dans 1.4.0.)

-XX: -PrintTenuringDistribution Imprime les informations relatives à l'âge des propriétaires.

Même si vous n'allez pas perturber la machine virtuelle Java avec des appels explicites à System.gc(), ils risquent de ne pas avoir l'effet escompté. Pour vraiment comprendre ce qui se passe dans la JVM avec la mémoire, lisez tout ce qui est écrit Brian Goetz .

5
Nick Holt

Si vous aimez une bonne façon de faire cela depuis la ligne de commande, utilisez jstat:

http://Java.Sun.com/j2se/1.5.0/docs/tooldocs/share/jstat.html

Il fournit des informations brutes à des intervalles configurables, ce qui est très utile pour la journalisation et la représentation graphique.

4
Pablojim

Si vous utilisez l'historique fourni par JMX des exécutions du GC, vous pouvez utiliser les mêmes chiffres avant/après, vous n'avez simplement pas à forcer un GC.

N'oubliez pas que ces exécutions de GC (généralement une pour l'ancienne et une pour la nouvelle génération) ne figurent pas sur des intervalles réguliers. Vous devez donc extraire également l'heure de début pour le traçage (ou pour un tracé avec un numéro de séquence pratiques qui suffiraient pour tracer).

Par exemple, sur Oracle HotSpot VM avec ParNewGC, il existe un MBean JMX appelé Java.lang:type=GarbageCollector,name=PS Scavenge, il a un attribut LastGCInfo, il retourne un CompositeData du dernier cycle de nettoyage de YG. Il est enregistré avec duration, absolu startTime et memoryUsageBefore et memoryUsageAfter.

Utilisez simplement une minuterie pour lire cet attribut. Chaque fois qu'un nouveau heure de début apparaît, vous savez qu'il décrit un nouvel événement du GC, vous extrayez les informations sur la mémoire et continuez à interroger la prochaine mise à jour. (Je ne sais pas si un AttributeChangeNotification peut être utilisé d'une manière ou d'une autre.)

Astuce: dans votre chronomètre, vous pouvez mesurer la distance jusqu'au dernier cycle CPG et, si elle est trop longue pour la résolution de votre tracé, vous pouvez invoquer System.gc () de manière conditionnelle. Mais je ne le ferais pas dans une instance OLTP.

2
eckes

Si vous utilisez Java 1.5, vous pouvez consulter ManagementFactory.getMemoryMXBean ()), qui vous donne des chiffres sur tous les types de mémoire. Heap et non-heap, perm-gen.

Un bon exemple peut être trouvé ici http://www.freshblurbs.com/explaining-Java-lang-outofmemoryerror-permgen-space

2
Zoukaye

Comme cela a été suggéré, essayez VisualVM pour obtenir une vue de base.

Vous pouvez également utiliser Eclipse MAT pour effectuer une analyse de la mémoire plus détaillée.

C'est correct de faire System.gc () tant que vous n'en dépendez pas, pour l'exactitude de votre programme.

0
Aakash

Le problème avec system.gc est que la machine virtuelle Java alloue déjà automatiquement du temps au garbage collector en fonction de l'utilisation de la mémoire.

Toutefois, si vous travaillez, par exemple, dans des conditions de mémoire très limitées, comme un périphérique mobile, System.gc vous permet d’allouer manuellement plus de temps à cette collecte de mémoire, mais au prix de cpu time (mais, comme vous l’avez dit plus tôt). , vous n’êtes pas préoccupé par les problèmes de performances de gc).

La meilleure pratique consisterait probablement à l’utiliser uniquement dans les cas où vous effectuez de grandes quantités de désallocation (comme vider un grand tableau).

Si vous êtes simplement préoccupé par l'utilisation de la mémoire, n'hésitez pas à appeler gc ou, mieux encore, à voir si cela fait une différence de mémoire importante dans votre cas, puis à prendre une décision.

0
bgw