java线程转储的评估

发布于 2024-08-26 22:32:04 字数 1940 浏览 8 评论 0 原文

我得到了我的一个进程的线程转储。它有一堆这样的线程。我猜他们保留了一堆内存,所以我遇到了 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. 堆栈跟踪中“锁定”的真正含义是什么?

Inflater.java 中的第 223 行是:

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

I got a thread dump of one of my processes. It has a bunch of these threads. I guess they are keeping a bunch of memory so I am getting 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

I am trying to find out how it arrived to this situation. CustomThreadedExtractorWrapper is a wrapper class that fires a thread to do some work (ExtractionThread, which uses ZipExtractorCommonsCompress to extract zip contents from a compressed stream). If the task is taking too long, ExtractionThread.interrupt() is called to cancel the operation.

I can see in my logs that the cancellation happened 25 times. And I see 21 of these threads in my dump. My questions:

  1. What is the status of these threads? Alive and running? Blocked somehow?
  2. They did not die with .interrupt() apparently? Is there a sure way to really kill a thread?
  3. What does really mean 'locked ' in the stack trace?

Line 223 in Inflater.java is:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

北城挽邺 2024-09-02 22:32:05

“锁定”意味着他们拥有监视器;也就是说,该方法是synchronized,并且线程转储显示执行同步的实例的地址。

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

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

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

"locked" means that they own a monitor; namely, the method is synchronized, and the thread dump shows the address of the instance on which synchronization is performed.

You can try to kill a thread with Thread.stop(), but the thread may resist, and it is inherently unsafe, deprecated, and very bad. Do not do it. Besides, I am not sure it works when the thread is in a native method, as is the case here.

Thread.interrupt() nudges the target thread. The thread will notice it the next time it either looks at the interrupt flag explicitly, or performs some potentially blocking operation (I/O, or wait()). The thread may catch the exception and ignore it.

Your threads are "runnable": they are not blocked. Inflater.inflate() is not a blocking function anyway; it performs in-memory computations only. There may be a bug in the native implementation (Inflater.inflateBytes(), but that's not very probable because this relies on Zlib, which is a very stable piece of code). More plausibly, one of the callers (e.g. your ZipExtractorCommonsCompress class) is stuck in a loop in which it asks the Zip extractor to process zero more bytes, and does not understand that it should wait for some more data before trying again.

窝囊感情。 2024-09-02 22:32:05
  1. 所有这些线程都处于可运行状态

  2. 中断不会杀死线程...它只是一个标志来指示线程是否被中断,方法 sleep , wait 和 all 都会在线程中断时抛出 InteruptedException。如果您想在中断时停止线程,请检查方法和 isInterupted() 并完成该线程中的所有工作

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

  1. All these threads are in runnable state

  2. interrupt will not a kill a thread... it is just a flag to indicate whether the thread is interrupted, methods sleep , wait and all will throw InteruptedException on thread interrupt. If you want to stop the thread on interuption check for the method and isInterupted() and finish all the work in that thread

  3. locked indicates that one particular object is locked by that thread

段念尘 2024-09-02 22:32:05

如果可能的话,我建议您尝试使用 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.

因此,上面跟踪中的两个线程都处于活动状态(注意,可运行意味着它们可以运行,不一定它们正在运行,即操作系统调度程序可能会让它们暂停,而另一个线程正在执行)。

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

  • 让未捕获的异常
  • 调用线程的 stop()
  • 让线程正常完成执行(即从 run() 退出)。

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

If possible I would recommend you try to use the jvisualvm (its in the bin folder of the JDK install). It can connect to any local java process and provide you with thread information and memory information (usage, allocated objects, etc). The interface is much easier to interpret than the console dumps. For your questions:

The definitions of Thread.State are in the 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.

So the two threads in your trace above are alive (note runnable means that they can run, not necessarily that they are running, i.e. the OS scheduler may have them paused while another thread is executing).

Possible ways to "kill" a thread:

  • Have an uncaught exception
  • call Thread's stop()
  • Have the thread complete execution normally (i.e. exit from run()).

For your third question, I am not sure, but I believe that is a reference to an internal lock that the thread is holding.

萌辣 2024-09-02 22:32:05

有没有一种确定的方法可以真正杀死一个线程?

不,没有。

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

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

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

Is there a sure way to really kill a thread?

No, there is not.

As you have observed Thread.interrupt() advises a thread to stop, but it may not notice, or it may decide to pay no attention.

The only other alternative is Thread.stop(), and that is deprecated because it can seriously destabilize an application. Specifically, Thread.stop() causes all of the threads locks to be released, without any guarantee that the state guarded by the locks is in a fit state to be visible. At the same time, the unexpected exception means that the methods that were interrupted by the stop() don't get a chance to (for example) notify() other threads that are waiting. Finally, it is possible for a thread to catch (and not rethrow) the ThreadDeath exception object, causing the stop() to not stop the thread at all.

In short calling Thread.stop() is a really, really bad idea.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文