如何分析一个Java线程转储?如何分析一个Java线程转储?(How to analyze a ja

2019-05-12 20:25发布

我想了解更多关于Java,尤其是内存管理和线程。 为此,我最近发现的看着线程转储的兴趣。

下面是使用VisualVM的,一个Java的内置工具从一个Web应用程序所采取的几行:

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

首先我对一些变量名的问题:

  • 是什么TID和NID是什么意思?
  • 什么是数字的平方括号后的Object.wait?

那么对于堆栈跟踪本身:

  • 这是什么意思等待<.....>(一java.lang中....),什么是在<..>
  • 这是什么意思锁定<.....>(一java.lang中....)同样的问题,什么是在<..>

我认为,锁定字好歹是有关等待状态,但是,我错了。 其实,我很奇怪,为什么锁定重复三次,但该线程中所看到的一样转储可运行状态:

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

然后,最后所有的,这是最严重的:

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

该线程处于可运行状态,但它的等待状态。 什么情况下,什么是0x00000?

为什么堆栈跟踪是没有线程类的任何迹象这么短呢?

如果你能回答我所有的问题,我将非常感激。

谢谢

Answer 1:

该TID是THEAD ID和NID是:本地线程ID。 此ID是高度依赖于平台。 这是NID在jstack线程转储。 在Windows上,它只是一个过程中的OS级线程ID。 在Linux和Solaris,它的螺纹(这又是一个轻量级进程)的PID。 在Mac OS X,它被认为是本机的pthread_t值。

转到此链接: Java的线程级ID :用于定义和这两个术语的进一步解释。

在IBM的网站上,我发现这个链接: 如何解释一个线程转储 。 覆盖此更详细:

这说明了什么就意味着等待:锁防止多个实体访问的共享资源。 用Java™每个对象具有相关联的锁(通过使用一个同步块或方法获得)。 在JVM的情况下,线程争夺JVM和锁在Java对象的各种资源。

然后,它描述了该显示器作为一种特殊的锁定机构的,其在JVM使用,以允许线程之间灵活的同步。 在本节的目的,阅读条款监督和互换锁定。

然后,它更进一步:

为了避免每一个对象上的显示器,JVM通常使用的标志在一个类或方法的块,以指示该项目已被锁定。 大多数时候,一块代码将过境的一些锁定部分而不争。 因此,家长标志就足以保护这段代码。 这就是所谓的平板显示器。 然而,如果另一个线程要访问一些代码已被锁定,已经发生真正的冲突。 在JVM现在必须创建(或膨胀)的监视器对象来保存所述第二线程并安排的信令机制,以协调访问代码部分。 现在该显示器被称为膨胀的监视器。

这里是你看到从线程转储线什么的更深入的解释。 Java线程由操作系统的本地线程来实现。 每个线程由粗体诸如线表示:

“线程1”(TID:0x9017A0,sys_thread_t:0x23EAC8,状态:R,天然ID:0x6E4)PRIO = 5

*下面的6项说明该正如我已经从例如它们匹配,在方括号[]值:

  1. 名称[ 线程-1],
  2. 标识符[0x9017A0]
  3. JVM的数据结构的地址[0x23EAC8]
  4. 当前状态[R],
  5. 本地线程标识符[0x6E4]
  6. 和优先级[5]。

在“等待”似乎与JVM本身,而不是应用程序线程深灰色相关联的守护线程。 当你得到一个“中的Object.wait()”,这意味着守护线程,“终结”在这里,对通知等待约一个锁定的对象上,在这种情况下,它显示了它在等待什么通知:“ -等待<0x27ef0288>(一个java.lang.ref.ReferenceQueue $锁定)”

所述的ReferenceQueue的定义是:引用队列中,向其中注册的引用对象被垃圾收集器所附被检测到适当的可到达性更改后。

终结器线程运行,这样的垃圾收集工作,清理与对象相关联的资源。 因为Java对象运行的方法java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:118),所以终结器线程是:如果我看到它corectly,终结不能获得锁到该对象锁定,直到该对象与它的当前任务完成。

另外,终结不只是希望回收内存,它比这更复杂的清理资源。 我需要做的就可以了更多的研究,但如果你有打开的文件,插座等...相关的对象的方法,那么,终结是要在释放这些项目的行动,以及工作。

什么是数字的平方括号后的Object.wait在线程转储?

它是在内存中的线程的指针。 这里是一个更详细的描述:

C.4.1线程信息

螺纹部分的第一部分示出了引起致命错误线程,如下所示:

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

线程指针的指针的Java虚拟机内螺纹结构。 这是一般的没有兴趣,除非你正在调试一个实时Java虚拟机或核心文件。

最后这说明来自: 故障排除指南对Java SE 6 HotSpot虚拟机

这里有一些更多的链接上的线程转储:

  • 线程如何工作
  • 如何分析线程转储
  • Java线程转储
  • Java虚拟机线程
  • 计算器问题: 线程是如何映射


Answer 2:

继@詹姆斯Drinkard的出色答卷:

需要注意的是,依赖于底层的实施方式中, java.lang.Thread.State中被阻止在一个本地方法一个线程可能被报告为RUNNABLE ,其中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.

事实证明,这说明还包括被封锁在操作系统调用,如投票或读操作 - 这可能是因为没有保证的JVM可以知道,当一个本地方法调用已阻止在操作系统级别。

JVM线程的许多讨论转储,我已经看到或者完全忽略这种可能性,或者轻率地掠过它没有考虑到影响 - 而不是其中最重要的是,监测工具可以混淆的报告说,几个这样的线程正在“跑步”,而且这它们都运行在100%。



文章来源: How to analyze a java thread dump?