当前位置: 首页 > 面试题库 >

如何分析Java线程转储?

越欣怡
2023-03-14
问题内容

我试图了解有关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?

为什么在没有任何线程类证据的情况下堆栈跟踪是如此之短?

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

谢谢


问题答案:

TID是主题ID,NID是:本机线程ID。此ID与平台高度相关。它是jstack线程转储中的NID。在Windows上,它只是进程中操作系统级别的线程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. 名称[ Thread-1 ],
  2. 标识符[ 0x9017A0 ],
  3. JVM数据结构地址[ 0x23EAC8 ],
  4. 当前状态[ R ],
  5. 本机线程标识符[ 0x6E4 ],
  6. 和优先级[ 5 ]。

“ wait on”似乎是与jvm本身关联的守护程序线程,而不是应用程序线程本身。 当您在Object.wait()中得到一个“”时,表示守护进程线程“
finalizer”正在等待有关对象锁定的通知,在这种情况下,它将向您显示它正在等待的通知:“-等待<0x27ef0288>(java.lang.ref.ReferenceQueue
$ Lock)”

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

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

另外,终结器不仅要回收内存,还涉及清理资源。我需要对其进行更多研究,但是如果您打开了与对象方法相关的文件,套接字等…,则终结器也将致力于释放这些项目。

线程转储中Object.wait之后的圆括号内的数字是什么?

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

C.4.1线程信息

线程部分的第一部分显示了引发致命错误的线程,如下所示:

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

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

最后的描述来自:具有HotSpot VM的Java SE6故障排除指南

以下是有关线程转储的更多链接:

  • 线程如何工作
  • 如何分析线程转储
  • Java线程转储


 类似资料:
  • 我试图了解更多关于java线程转储的信息。我正在使用JBOSS EAP 4.3。 目前,我在我的一个环境中面临性能问题。突然,CPU利用率上升到700%。我把线程转储了,它是一个巨大的文件。 我在我的threaddump中发现了很多下面等待的线程条目。 我想从上面的等待线程中理解。是什么导致CPU利用率上升?

  • 问题内容: 我正在用Python开发一个固有的多线程模块,我想找出它在哪里花时间。cProfile似乎仅分析主线程。有什么方法可以分析计算中涉及的所有线程? 问题答案: 请参阅yappi(另一个Python Profiler)。

  • 本文向大家介绍Java线程同步实例分析,包括了Java线程同步实例分析的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了Java线程同步的用法。分享给大家供大家参考。具体分析如下: 多线程的使用为我们的程序提供了众多的方便,同时它也给我们带来了以往没有考虑过的麻烦。当我们使用多线程处理共享资源时意外将会发生:比如我们一起外出就餐,每个人都是一个线程,餐桌上的食物则是共享资源,当我看到红烧鸡腿

  • 本文向大家介绍Java线程调度之线程休眠用法分析,包括了Java线程调度之线程休眠用法分析的使用技巧和注意事项,需要的朋友参考一下 本文实例分析了Java线程调度之线程休眠用法。分享给大家供大家参考。具体分析如下: Java线程调度是Java多线程的核心,只有良好的调度,才能充分发挥系统的性能,提高程序的执行效率。   这里要明确的一点,不管程序员怎么编写调度,只能最大限度的影响线程执行的次序,而

  • 本文向大家介绍Java 多线程使用要点分析,包括了Java 多线程使用要点分析的使用技巧和注意事项,需要的朋友参考一下 多线程细节问题 sleep方法和wait方法的异同点? 相同点: 让线程处于冻结状态. 不同点: sleep必须指定时间 wait可以指定时间也可以不指定时间 sleep时间到,线程处于临时阻塞状态或者运行态 wait如果没有时间,必须通过notify或者notifyAll唤醒