Comment analyser un vidage de thread java?


J'essaie de comprendre plus sur java, en particulier sur la gestion de la mémoire et les threads. Pour cette raison, j'ai récemment trouvé un intérêt à regarder les vidages de threads.

Voici quelques lignes tirées d'une application web utilisant VisualVM, un outil intégré pour java:

"Finalizer" daemon prio=8 tid=0x02b3d000 nid=0x898 in Object.wait() [0x02d0f000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x27ef0288> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:118)
    - locked <0x27ef0288> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:134)
    at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159)

   Locked ownable synchronizers:
    - None

"Reference Handler" daemon prio=10 tid=0x02b3b800 nid=0x494 in Object.wait() [0x02cbf000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x27ef0310> (a java.lang.ref.Reference$Lock)
    at java.lang.Object.wait(Object.java:485)
    at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116)
    - locked <0x27ef0310> (a java.lang.ref.Reference$Lock)

J'ai d'abord des questions sur certains noms de variables:

  • que signifient tid et nid?
  • Quelle est la figure entre parenthèses au carré après l'objet.attendre?

Puis pour la pile trace elle-même:

  • qu'est-ce que cela signifie attendre <.....> (Java.lang....) et quel est le nombre de <..>
  • qu'est-ce que cela signifie verrouillé <.....> (Java.lang....) même question, qu'y a-t-il dans <..>

Je pensais que le mot verrouillé était lié en quelque sorte à une condition d'attente, cependant, j'avais tort. En fait, je me demande pourquoi locked est répété trois fois, mais le thread est dans un état runnable comme on le voit dans le même vidage:

"Thread-0" prio=6 tid=0x02ee3800 nid=0xc1c runnable [0x03eaf000]
   java.lang.Thread.State: RUNNABLE
    at java.io.FileInputStream.readBytes(Native Method)
    at java.io.FileInputStream.read(FileInputStream.java:199)
    at java.io.BufferedInputStream.read1(BufferedInputStream.java:256)
    at java.io.BufferedInputStream.read(BufferedInputStream.java:317)
    - locked <0x23963378> (a java.io.BufferedInputStream)
    at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:264)
    at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:306)
    at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:158)
    - locked <0x23968450> (a java.io.InputStreamReader)
    at java.io.InputStreamReader.read(InputStreamReader.java:167)
    at java.io.BufferedReader.fill(BufferedReader.java:136)
    at java.io.BufferedReader.readLine(BufferedReader.java:299)
    - locked <0x23968450> (a java.io.InputStreamReader)
    at java.io.BufferedReader.readLine(BufferedReader.java:362)
    at org.codehaus.plexus.util.cli.StreamPumper.run(StreamPumper.java:145)

Enfin, c'était le pire d'entre eux:

"CompilerThread0" daemon prio=10 tid=0x02b81000 nid=0x698 waiting on condition [0x00000000]
   java.lang.Thread.State: RUNNABLE

Ce thread est en état d'exécution, mais il attend à condition. Quelle condition et qu'est-ce que 0x00000?

Pourquoi la trace de la pile est si courte sans aucune preuve de la classe thread?

Si vous pouviez répondre à toutes mes questions, je vous serais très reconnaissant.

Merci

Author: James Drinkard, 2011-09-29

3 answers

Le TID est thead id et NID est: Native thread ID. Cet ID dépend fortement de la plate-forme. C'est le NID dans les vidages de threads jstack. Sous Windows, il s'agit simplement de l'ID de thread au niveau du système d'exploitation dans un processus. Sur Linux et Solaris, c'est le PID du thread (qui à son tour est un processus léger). Sur Mac OS X, il est dit que c'est la valeur native pthread_t.

Allez sur ce lien: Java-level thread ID : pour une définition et une explication supplémentaire de ces deux termes.

Sur le site d'IBM J'ai trouvé ce lien: Comment interpréter un vidage de thread . cela couvre cela plus en détail:

Il explique ce que signifie attendre: Un verrou empêche plusieurs entités d'accéder à une ressource partagée. Chaque objet dans Java™ a un verrou associé (obtenu en utilisant un bloc ou une méthode synchronisée). Dans le cas de la JVM, les threads sont en concurrence pour diverses ressources dans la JVM et verrous sur les objets Java.

Ensuite, il décrit le moniteur comme un type spécial de mécanisme de verrouillage qui est utilisé dans la JVM pour permettre une synchronisation flexible entre les threads. Pour les besoins de cette section, lisez les termes surveiller et verrouiller de manière interchangeable.

, Puis il va plus loin:

Pour éviter d'avoir un moniteur sur chaque objet, la JVM utilise généralement un indicateur dans un bloc de classe ou de méthode pour indiquer que l'élément est verrouillé. La plupart du temps, un morceau de code transitera une section verrouillée sans conflit. Par conséquent, le drapeau guardian est suffisant pour protéger ce morceau de code. Ce est appelé un moniteur plat. Cependant, si un autre thread souhaite accéder à du code verrouillé, un conflit véritable s'est produit. La JVM doit maintenant créer (ou gonfler) l'objet monitor pour contenir le deuxième thread et organiser un mécanisme de signalisation pour coordonner l'accès à la section de code. Ce moniteur est maintenant appelé un moniteur gonflé.

Voici une explication plus approfondie de ce que vous voyez sur les lignes du vidage de threads. Un thread Java est implémenté par un thread natif le système d'exploitation. Chaque thread est représenté par une ligne en gras telle que:

"Thread-1" (TID:0x9017A0, sys_thread_t:0x23EAC8, état:R, ID natif:0x6E4) prio=5

*Les 6 éléments suivants expliquent cela car je les ai appariés à partir de l'exemple, valeurs entre parenthèses []:

  1. nom [Fil-1],
  2. identificateur [0x9017A0],
  3. Adresse de la structure de données JVM [ 0x23EAC8],
  4. état actuel [R],
  5. identifiant de thread natif [ 0x6E4],
  6. et la priorité [5].

Le "wait on" semble être un thread de démon associé à la jvm elle-même et non au thread d'application perse. Lorsque vous obtenez un " dans l'objet.wait ()", cela signifie que le thread démon," finalizer " ici, attend une notification sur un verrou sur un objet, dans ce cas, il vous montre quelle notification il attend: "- en attente sur (un Java.lang.réf.ReferenceQueue Lock Lock)"

Définition de la ReferenceQueue est: Files d'attente de référence, auxquelles les objets de référence enregistrés sont ajoutés par le garbage collector après la détection des modifications d'accessibilité appropriées.

Le thread finalizer s'exécute de sorte que le garbage collection fonctionne pour nettoyer les ressources associées à un objet. Si je le vois corectly, le finaliseur ne peut pas obtenir le verrou de cet objet: Java.lang.réf.RéférenceQueue.supprimer (ReferenceQueue.java: 118) parce que l'objet java exécute une méthode, le thread finalizer est donc verrouillé jusqu'à ce que cet objet ait terminé sa tâche actuelle.

De plus, le finaliseur ne cherche pas seulement à récupérer de la mémoire, il est plus impliqué que cela pour nettoyer les ressources. J'ai besoin de faire plus d'études à ce sujet, mais si vous avez des fichiers ouverts, des sockets, etc... lié à une méthode d'objets, alors le finaliseur va travailler à libérer ces éléments comme Bien.

Quelle est la figure entre parenthèses au carré après l'objet.attendre dans le thread dump?

C'est un pointeur en mémoire vers le thread. Voici une description plus détaillée:

C. 4.1 Informations sur le fil

La première partie de la section thread montre le thread qui a provoqué l'erreur fatale, comme suit:

Current thread (0x0805ac88):  JavaThread "main" [_thread_in_native, id=21139]
                    |             |         |            |          +-- ID
                    |             |         |            +------------- state
                    |             |         +-------------------------- name
                    |             +------------------------------------ type
                    +-------------------------------------------------- pointer

Le pointeur de thread est le pointeur vers la structure de thread interne de la machine virtuelle Java. Cela n'a généralement aucun intérêt sauf si vous déboguez une machine virtuelle Java en direct ou un fichier de base.

Cette dernière description vient de: Guide de dépannage pour Java SE 6 avec HotSpot VM

Voici quelques liens supplémentaires sur les vidages de threads:

 103
Author: James Drinkard, 2018-08-10 02:04:39

Suite à l'excellente réponse de @James Drinkard:

Notez que, selon l'implémentation sous-jacente, le java.lang.Fil.L'état d'un thread est bloqué dans une méthode native peut être déclaré comme RUNNABLE, où A thread in the runnable state is executing in the Java virtual machine but it may be waiting for other resources from the operating system such as processor.

Il s'avère que cette description englobe également le blocage dans un appel de système d'exploitation tel qu'une opération de sondage ou de lecture - probablement parce qu'il n'y a aucune garantie que la JVM puisse savoir quand un appel de méthode native a bloqué sur le système d'exploitation niveau.

De nombreuses discussions sur les vidages de threads JVM que j'ai vues ignorent complètement cette possibilité, ou la parcourent allègrement sans tenir compte des implications - notamment le fait que les outils de surveillance peuvent signaler de manière confuse que plusieurs de ces threads sont "en cours d'exécution", et en outre qu'ils fonctionnent tous à 100%.

 6
Author: Jeremy, 2016-04-06 17:47:35

Essayer http://fastthread.io

C'est probablement suffisant pour de nombreux cas.

 5
Author: Jaskey, 2016-11-23 03:14:03