Come analizzare un dump di thread java?


Sto cercando di capire di più su java, in particolare sulla gestione della memoria e sui thread. Per questo motivo ho recentemente trovato interesse a guardare i dump dei thread.

Ecco alcune righe tratte da un'app web che utilizza VisualVM, uno strumento integrato per 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)

Per prima cosa ho domande su alcuni nomi di variabili:

  • cosa significano tid e nid?
  • Qual è la figura tra parentesi al quadrato dopo l'Oggetto.aspetta?

Quindi per lo stack traccia stessa:

  • cosa significa in attesa <.....> (Java.lang....) e qual è il numero in <..>
  • cosa significa bloccato <.....> (Java.lang....) stessa domanda, cosa c'è in <..>

Pensavo che la parola locked fosse in qualche modo correlata a una condizione di attesa, tuttavia, mi sbagliavo. In effetti, mi chiedo perché locked venga ripetuto tre volte, ma il thread è in stato eseguibile come visto nello stesso dump:

"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)

Poi, ultimo di tutti, questo è stato il peggiore di loro:

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

Questo thread è in stato eseguibile, ma è in attesa a condizione. Quale condizione e che cosa è 0x00000?

Perché la traccia dello stack è così breve senza alcuna prova della classe thread?

Se potessi rispondere a tutte le mie domande ti sarei molto grato.

Grazie

Author: James Drinkard, 2011-09-29

3 answers

Il TID è l'idad e il NID è: Native thread ID. Questo ID è altamente dipendente dalla piattaforma. È il NID nei dump del thread jstack. Su Windows, è semplicemente l'ID thread a livello di sistema operativo all'interno di un processo. Su Linux e Solaris, è il PID del thread (che a sua volta è un processo leggero). Su Mac OS X, si dice che sia il valore pthread_t nativo.

Vai a questo link: Java-level thread ID : per una definizione e un'ulteriore spiegazione di questi due termini.

Sul sito di IBM Ho trovato questo link: Come interpretare un dump di thread. che copre questo in modo più dettagliato:

Spiega cosa significa aspettare: Un blocco impedisce a più di un'entità di accedere a una risorsa condivisa. Ogni oggetto in Java™ ha un blocco associato (ottenuto utilizzando un blocco o un metodo sincronizzato). Nel caso della JVM, i thread competono per varie risorse nella JVM e si bloccano sugli oggetti Java.

Quindi descrive il monitor come un tipo speciale di meccanismo di blocco che viene utilizzato nella JVM per consentire la sincronizzazione flessibile tra i thread. Ai fini di questa sezione, leggere i termini monitorare e bloccare in modo intercambiabile.

Poi va oltre:

Per evitare di avere un monitor su ogni oggetto, la JVM di solito utilizza un flag in un blocco di classe o metodo per indicare che l'elemento è bloccato. La maggior parte delle volte, un pezzo di codice transiterà in una sezione bloccata senza contesa. Pertanto, la bandiera guardian è sufficiente per proteggere questo pezzo di codice. Questo è chiamato un monitor piatto. Tuttavia, se un altro thread desidera accedere a un codice bloccato, si è verificata una vera contesa. La JVM deve ora creare (o gonfiare) l'oggetto monitor per contenere il secondo thread e predisporre un meccanismo di segnalazione per coordinare l'accesso alla sezione del codice. Questo monitor è ora chiamato un monitor gonfiato.

Ecco una spiegazione più approfondita di ciò che stai vedendo sulle linee dal dump del thread. Un thread Java è implementato da un thread nativo del sistema operativo. Ogni thread è rappresentato da una riga in grassetto come:

"Per maggiori informazioni, consulta la nostra informativa sulla privacy.=5

* I seguenti 6 elementi spiegano questo come li ho abbinati dall'esempio, valori tra parentesi []:

  1. nome [Thread-1],
  2. identificatore [ 0x9017A0],
  3. Indirizzo struttura dati JVM [ 0x23EAC8],
  4. stato attuale [R],
  5. identificatore di thread nativo [ 0x6E4],
  6. e priorità [5].

Il "wait on" sembra essere un thread daemon associato alla jvm stessa e non al thread dell'applicazione perse. Quando si ottiene un oggetto " in.wait()", ciò significa che il thread del demone, "finalizer" qui, è in attesa di una notifica su un blocco su un oggetto, in questo caso mostra quale notifica è in attesa: "- in attesa di (a Java.lang.rif.ReferenceQueue Lock Blocca)"

La definizione di ReferenceQueue è: Code di riferimento, a cui gli oggetti di riferimento registrati vengono aggiunti dal garbage collector dopo che vengono rilevate le modifiche di raggiungibilità appropriate.

Il thread finalizzatore viene eseguito in modo che la garbage collection funzioni per ripulire le risorse associate a un oggetto. Se lo vedo in modo coretto, il finalizzatore non può ottenere il blocco di questo oggetto: Java.lang.rif.ReferenceQueue.rimuovere (ReferenceQueue.java: 118)poiché l'oggetto java sta eseguendo un metodo, quindi il thread di finalizzatore è bloccato fino a quando l'oggetto non è terminato con l'attività corrente.

Inoltre, il finalizzatore non sta solo cercando di recuperare memoria, è più coinvolto di quello per ripulire le risorse. Ho bisogno di fare più studio su di esso, ma se hai file aperti, socket, ecc... relativo a un metodo di oggetti, il finalizzatore funzionerà per liberare tali elementi come bene.

Qual è la figura tra parentesi al quadrato dopo l'Oggetto.aspetta nel scarico del filo?

È un puntatore in memoria al thread. Ecco una descrizione più dettagliata:

C. 4. 1 Informazioni sul thread

La prima parte della sezione thread mostra il thread che ha provocato l'errore fatale, come segue:

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

Il puntatore del thread è il puntatore alla struttura del thread interno della VM Java. Generalmente non è di alcun interesse a meno che non si stia eseguendo il debug una VM Java live o un file core.

Quest'ultima descrizione proviene da: Guida alla risoluzione dei problemi per Java SE 6 con HotSpot VM

Ecco alcuni altri link sui dump dei thread:

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

Oltre all'eccellente risposta di @James Drinkard:

Si noti che, a seconda dell'implementazione sottostante, il java.lang.Thread.Lo stato di un thread bloccato in un metodo nativo può essere segnalato come RUNNABLE, dove 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.

Si scopre che questa descrizione comprende anche il blocco in una chiamata del sistema operativo come un'operazione di poll o read-presumibilmente perché non vi è alcuna garanzia che la JVM possa sapere quando una chiamata al metodo nativo è stata bloccata nel sistema operativo livello.

Molte discussioni sui dump dei thread JVM che ho visto ignorano completamente questa possibilità, o sfiorano allegramente senza considerare le implicazioni - non ultimo dei quali è che gli strumenti di monitoraggio possono riferire confusamente che molti di questi thread sono "in esecuzione", e inoltre che sono tutti in esecuzione al 100%.

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

Prova http://fastthread.io

Questo è probabilmente sufficiente per molti casi.

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