0

在对生产环境中的一个 jvm 挂起问题进行故障排除时,我们遇到了执行以下记录器语句的线程之一

logger.debug("Loaded ids as " + ids + ".");

在这一步挂起,线程状态为可运行。这里 ids 是一个集合。还有另一个线程通过倒计时锁存器等待上述线程以完成其任务。该软件每 15 分钟进行一次线程转储,两个线程的堆栈跟踪如下所示

Stack trace for [THREAD GROUP: Job_Executor] [THREAD NAME:main-Runner Thread][THREAD STATE: WAITING]
    ...sun.misc.Unsafe.park(Native Method)
    ...java.util.concurrent.locks.LockSupport.park(Unknown Source)
    ...java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(Unknown Source)
    ...java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(Unknown Source)
    ...java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(Unknown Source)
    ...java.util.concurrent.CountDownLatch.await(Unknown Source)
    ...com.runner.MainRunner.stopThread(MainRunnerRunner.java:1334)


Stack trace for [THREAD GROUP: Job_Executor] [THREAD NAME:task executor][THREAD STATE: RUNNABLE]    
    ...java.util.AbstractCollection.toString(Unknown Source)           
    ...java.lang.String.valueOf(Unknown Source)      
    ...java.lang.StringBuilder.append(Unknown Source)    
    ...com.runner.CriticalTaskExecutor.loadByIds(CriticalTaskExecutor.java:143)

这个 jvm 挂了将近 24 小时,最后我们不得不杀死它才能继续前进。线程转储表明有 43 个线程处于 RUNNABLE 状态,包括上述线程。

上述线程在执行 collection.toString() 时处于 RUNNABLE 状态 24 小时的原因可能是什么?

关于如何进行的任何建议?

4

2 回答 2

1

上述线程在执行 collection.toString() 时处于 RUNNABLE 状态 24 小时的原因可能是什么?

您没有提供足够的信息来诊断问题。我只会挑战你不要假设这里发生了 JVM 问题。

如果我们查看该AbstractCollection.toString()方法的源代码,我们会发现它遍历集合并输出大约“[item0, item1, item2]”。调用每个item.toString()方法来显示项目。

如果应用程序挂起在集合中,toString()那么我的猜测是集合上的迭代器存在问题。如果您的应用程序正在旋转,您可以知道这一点——使用接近 100% 的 CPU。也许hasNext()上的方法Set总是返回true

如果应用程序挂起实际上是在内部,item.toString()那么我会确保您的项目只是显示简单的字段。请注意如果访问会进行 RPC 调用的字段,例如延迟加载的 ORM 包装字段。

如果您提供有关Set问题的详细信息并显示id.toString()代码,我们可以提供更多帮助。

现在听起来这是一组Integer对象。不知道为什么这会挂起您的应用程序。这里有几个其他的想法:

  • 您是否以非同步方式访问此集合?是否有多个线程对集合进行了更改,从而导致其迭代器旋转而损坏?您可以尝试将其包装在Collections.synchronizedSet(...).
  • 任何机会Set都是巨大的并且您正在运行接近内存不足并且程序正在颠簸?但是,这不会挂起您的应用程序,而只会使其缓慢爬行。你会开始看到内存不足的异常。
  • 有没有机会toString()被一遍又一遍地调用?我假设您会在日志中看到这一点。
于 2012-10-09T13:58:51.797 回答
0

这取决于toString()被调用的方法。当正在构建的堆对于堆来说太大时,我已经看到AbstractCollection.toString跌倒。String否则,问题可能出toString在集合中的对象上。

要弄清楚它是哪一个,需要更多的堆栈转储(10 个左右)。卡住的线程可能通常是toString导致问题的原因。

作为快速修复,更换

logger.debug("Loaded ids as " + ids + ".");

logger.debug("Loaded ids as {}.", ids);

(假设您使用的是 slf4j,否则在您的框架中查找适当的方法来进行参数化日志记录)。

如果未启用调试,这将跳过 toString。

于 2012-10-09T13:50:26.863 回答