评估java线程转储

时间:2010-03-30 12:28:14

标签: java thread-dump

我得到了一个我的进程的线程转储。它有很多这些线程。我猜他们保留了一大堆内存,所以我得到了OOM。

"Thread-8264" prio=6 tid=0x4c94ac00 nid=0xf3c runnable [0x4fe7f000]
   java.lang.Thread.State: RUNNABLE
    at java.util.zip.Inflater.inflateBytes(Native Method)
    at java.util.zip.Inflater.inflate(Inflater.java:223)
    - locked <0x0c9bc640> (a java.util.zip.Inflater)
    at org.apache.commons.compress.archivers.zip.ZipArchiveInputStream.read(ZipArchiveInputStream.java:235)
    at com.my.ZipExtractorCommonsCompress.extract(ZipExtractorCommonsCompress.java:48)
    at com.my.CustomThreadedExtractorWrapper$ExtractionThread.run(CustomThreadedExtractorWrapper.java:151)

   Locked ownable synchronizers:
    - None

"Thread-8241" prio=6 tid=0x4c94a400 nid=0xb8c runnable [0x4faef000]
   java.lang.Thread.State: RUNNABLE
    at java.util.zip.Inflater.inflateBytes(Native Method)
    at java.util.zip.Inflater.inflate(Inflater.java:223)
    - locked <0x0c36b808> (a java.util.zip.Inflater)
    at org.apache.commons.compress.archivers.zip.ZipArchiveInputStream.read(ZipArchiveInputStream.java:235)
    at com.my.ZipExtractorCommonsCompress.extract(ZipExtractorCommonsCompress.java:48)
    at com.my.CustomThreadedExtractorWrapper$ExtractionThread.run(CustomThreadedExtractorWrapper.java:151)

   Locked ownable synchronizers:
    - None

我试图找出它是如何达到这种情况的。 CustomThreadedExtractorWrapper是一个包装类,它触发一个线程来完成一些工作(ExtractionThread,它使用ZipExtractorCommonsCompress从压缩流中提取zip内容)。如果任务花费的时间过长,则会调用ExtractionThread.interrupt()来取消操作。

我可以在我的日志中看到取消发生了25次。我在转储中看到了21个这样的线程。我的问题:

  1. 这些主题的状态是什么?活着还在跑步?不知怎的?
  2. 他们显然没有死于.interrupt()?有没有办法真正杀死一个线程?
  3. 在堆栈跟踪中真正意味着“锁定”的是什么?
  4. Inflater.java中的第223行是:

    public synchronized int inflate(byte[] b, int off, int len) {
        ...
        //return is line 223
        return inflateBytes(b, off, len);                          
    }
    

4 个答案:

答案 0 :(得分:3)

“锁定”意味着他们拥有一台显示器;即,方法为synchronized,并且线程转储显示执行同步的实例的地址。

您可以尝试使用Thread.stop()来杀死一个帖子,但线程可能会抵制,并且它本质上是不安全的,已弃用且非常糟糕。不要做。此外,当线程处于本机方法时,我不确定它是否有效,就像这里的情况一样。

Thread.interrupt()轻推目标线程。线程将在下次明确查看中断标志或执行某些可能的阻塞操作(I / O或wait())时注意到它。线程可以捕获异常并忽略它。

你的线程是“可运行的”:它们没有被阻止。 Inflater.inflate()无论如何都不是阻止功能;它只执行内存计算。本机实现中可能存在一个错误(Inflater.inflateBytes(),但这不太可能,因为这依赖于Zlib,这是一段非常稳定的代码)。更合理的是,其中一个调用者(例如你的ZipExtractorCommonsCompress类)被卡在一个循环中,它要求Zip提取器处理零个字节,并且不知道它应该等待更多的数据然后再次尝试

答案 1 :(得分:2)

  1. 所有这些线程都处于可运行状态

  2. 中断不会杀死一个线程......它只是一个标志,指示线程是否被中断,方法是否休眠,等待并且所有都会在线程中断上抛出InteruptedException。如果你想在interuption上停止线程检查方法和isInterupted()并完成该线程中的所有工作

  3. locked表示该线程锁定了一个特定对象

答案 2 :(得分:0)

如果可能,我建议你尝试使用jvisualvm(它在JDK安装的bin文件夹中)。它可以连接到任何本地java进程,并为您提供线程信息和内存信息(用法,分配的对象等)。该接口比控制台转储更容易解释。对于你的问题:

Thread.State的定义在API中:

NEW - A thread that has not yet started is in this state.
RUNNABLE - A thread executing in the Java virtual machine is in this state.
BLOCKED - A thread that is blocked waiting for a monitor lock is in this state.
WAITING - A thread that is waiting indefinitely for another thread to perform a particular action is in this state.
TIMED_WAITING - A thread that is waiting for another thread to perform an action for up to a specified waiting time is in this state.
TERMINATED - A thread that has exited is in this state.

因此上面跟踪中的两个线程是活动的(注意runnable意味着它们可以运行,不一定是它们正在运行,即OS调度程序可能在另一个线程正在执行时暂停它们。)

“杀死”线程的可能方法:

  • 有未被捕获的例外
  • 调用Thread的stop()
  • 让线程正常完成执行(即退出run())。

对于你的第三个问题,我不确定,但我相信这是对线程持有的内部锁的引用。

答案 3 :(得分:0)

  

有没有办法真正杀死一个帖子?

不,没有。

正如您所观察到的Thread.interrupt()建议线程停止,但它可能没有注意到,或者它可能决定不关注。

唯一的另一种选择是Thread.stop(),这是不推荐使用的,因为它会严重破坏应用程序的稳定性。具体来说,Thread.stop()导致释放所有线程锁,而不保证锁被保护的状态处于适合状态以便可见。同时,意外异常意味着被stop()中断的方法没有机会(例如)notify()等待的其他线程。最后,线程可能捕获(而不是重新抛出)ThreadDeath异常对象,导致stop()根本不停止线程。

简而言之,调用Thread.stop()是一个非常非常糟糕的主意。