java - 如何分析java线程转储?

标签 java multithreading thread-dump

我试图更多地了解 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....) 是什么意思,<..> 中的数字是多少
  • 这是什么意思锁定 <.....> (a java.lang....) 同样的问题,<..> 中有什么

  • 我认为锁定这个词在某种程度上与等待条件有关,但是,我错了。事实上,我想知道为什么locked被重复了3次,但是在同一个转储中看到的线程处于可运行状态:
    "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?

    为什么堆栈跟踪如此短而没有线程类的任何证据?

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

    谢谢

    最佳答案

    TID 是 thead id,NID 是: native 线程 ID。此 ID 高度依赖于平台。它是 jstack 线程转储中的 NID。在 Windows 上,它只是进程内的操作系统级线程 ID。在 Linux 和 Solaris 上,它是线程的 PID(它又是一个轻量级进程)。在 Mac OS X 上,它被称为 native pthread_t 值。

    转到此链接:Java-level thread ID :对于这两个术语的定义和进一步解释。

    在 IBM 的网站上,我找到了这个链接:How to interpret a thread dump .更详细地介绍了这一点:

    它解释了等待意味着什么:
    锁可防止多个实体访问共享资源。 Java™ 中的每个对象都有一个关联的锁(通过使用同步块(synchronized block)或方法获得)。在 JVM 的情况下,线程竞争 JVM 中的各种资源并锁定 Java 对象。

    然后它将监视器描述为一种特殊的锁定机制,用于 JVM 中以允许线程之间的灵活同步。就本节而言,请交替阅读术语监视器和锁定。

    然后它更进一步:

    为了避免在每个对象上都有一个监视器,JVM 通常在类或方法块中使用一个标志来指示该项目被锁定。大多数时候,一段代码会在没有争用的情况下通过某个锁定的部分。因此,监护人标志足以保护这段代码。这称为平板显示器。然而,如果另一个线程想要访问一些被锁定的代码,那么就会发生真正的争用。 JVM 现在必须创建(或扩充)监视器对象以保存第二个线程并安排信号机制来协调对代码部分的访问。该监视器现在称为充气监视器。

    这是对您在线程转储中看到的内容的更深入的解释。 Java 线程由操作系统的本地线程实现。每个线程由粗体线表示,例如:

    "Thread-1"(TID:0x9017A0, sys_thread_t:0x23EAC8, state:R, native ID:0x6E4) prio=5

    *以下 6 项解释了这一点,因为我从示例中匹配了它们,括号 [] 中的值:

  • 姓名 [ 线程 1 ],
  • 标识符 [ 0x9017A0 ],
  • JVM数据结构地址[ 0x23EAC8 ],
  • 当前状态 [ R ],
  • native 线程标识符 [ 0x6E4 ],
  • 和优先级 [ 5 ]。

  • “等待”似乎是与 jvm 本身相关的守护线程,而不是应用程序线程本身。当你得到一个“in Object.wait()”时,这意味着守护进程线程,这里的“终结器”,正在等待一个关于对象锁定的通知,在这种情况下,它会向你显示它正在等待的通知:
    “- 等待 <0x27ef0288>(一个 java.lang.ref.ReferenceQueue$Lock)”

    ReferenceQueue 的定义是:
    引用队列,在检测到适当的可达性更改后,垃圾收集器会将注册的引用对象附加到该队列中。

    终结器线程运行,因此垃圾收集操作以清理与对象关联的资源。如果我正确地看到它,终结器无法获得此对象的锁: java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:118) 因为 java 对象正在运行一个方法,所以终结器线程是锁定,直到该对象完成其当前任务。

    此外,终结器不仅仅是为了回收内存,它比清理资源更重要。我需要对其进行更多研究,但是如果您打开了文件、套接字等...与对象方法相关,那么终结器也将致力于释放这些项目。

    What is the figure in squared parenthesis after Object.wait in the thread dump?



    它是内存中指向线程的指针。这是更详细的描述:

    C.4.1 线程信息

    线程部分的第一部分显示了引发致命错误的线程,如下所示:
    Current thread (0x0805ac88):  JavaThread "main" [_thread_in_native, id=21139]
                        |             |         |            |          +-- ID
                        |             |         |            +------------- state
                        |             |         +-------------------------- name
                        |             +------------------------------------ type
                        +-------------------------------------------------- pointer
    

    线程指针是指向 Java VM 内部线程结构的指针。除非您正在调试实时 Java VM 或核心文件,否则通常不会对其感兴趣。

    最后的描述来自:Troubleshooting Guide for Java SE 6 with HotSpot VM

    以下是有关线程转储的更多链接:
  • How Threads Work
  • How to Analyze a Thread Dump
  • Java Thread Dumps
  • Java VM threads
  • Stackoverflow 问题:How threads are mapped
  • 关于java - 如何分析java线程转储?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7599608/

    相关文章:

    java - 如何使用 JAXB (Intellij Idea) 从多个 xsd 生成 Java 类

    c# - IIS 线程无法启动 C#

    java - 在 Windows 10 机器上最新版本的 Java 上崩溃的 fatal error

    java - 有没有一种简单的方法为每个运行的jvm生成jstack?

    java - 带有 SurfaceView 和逻辑单元的 Android 游戏

    java - 线程转储之间有什么区别

    java - java spring 禁止的 Ajax 删除请求

    java - 在 Hazelcast XML 配置中使用属性文件值

    java - 广播接收器类将状态发送到 fragment

    java - 多线程中的ExecuteQuery关闭hsqldb数据库连接