【问题标题】:Taking thread dumps in production在生产中进行线程转储
【发布时间】:2012-12-16 14:29:31
【问题描述】:

我正在分析进行线程转储的方法之间的差异。以下是我正在研究的其中几个

  1. 定义一个 jmx bean,在单击声明的 bean 操作时通过 Runtime.exec() 触发 jstack。

  2. 在预定义的时间间隔后重复执行“ManagementFactory.getThreadMXBean().dumpAllThreads(true, true)”的守护线程。

比较两者之间的线程转储输出,我发现方法 2 存在以下缺点

  1. 使用方法 2 记录的线程转储无法被 TDA 等开源线程转储分析器解析
  2. 输出不包括在分析高 CPU 问题时可能有用的本机线程 ID(对吗?)
  3. 还有吗?

我希望得到有关方面的建议/意见

  1. 在生产代码中通过 Runtime.exec() 执行 jstack 有什么缺点吗?各种操作系统(windows、linux)上的兼容性问题?

  2. 还有其他获取线程转储的方法吗?

谢谢。

编辑 -

1 和 2 的组合方法似乎是要走的路。我们可以在后台运行一个专用线程,并以线程转储分析器可以理解的格式在日志文件中打印线程转储。 如果需要任何仅由 jstack 输出记录的额外信息(比如可能是本机线程 id),我们会根据需要手动执行。

【问题讨论】:

  • 这是否与 JEE 应用程序有关?

标签: java runtime.exec thread-dump


【解决方案1】:

在 Java 8 中,jcmd 是首选方法。

jcmd <PID> Thread.print

以下是来自Oracle documentation 的sn-p:

JDK 8 的发布引入了 Java Mission Control、Java Flight Recorder 和 jcmd 实用程序,用于诊断 JVM 和 Java 应用程序的问题。 建议使用最新的实用程序 jcmd 而不是以前的 jstack 实用程序,以增强诊断并降低性能开销。

但是,将其与应用程序一起提供可能会涉及许可问题,我不确定。

【讨论】:

  • 很高兴知道。它们可以被 TDA 等开源线程转储分析器解析吗?它们是否包含本机线程 ID?
【解决方案2】:

你可以使用

jstack {pid} > stack-trace.log

以用户身份在进程运行的盒子上运行。

如果您多次运行此操作,您可以使用diff 更轻松地查看哪些线程处于活动状态。


为了分析堆栈跟踪,我在专用线程中定期使用以下采样。

 Map<Thread, StackTraceElement[]> allStackTraces = Thread.getAllStackTraces();

使用此信息,您可以获得线程的 id、运行状态并比较堆栈跟踪。

【讨论】:

  • 执行jstack的第一点和我上面提到的方法1一样吗?通过 jmx 集成和触发它可以帮助用户不必担心进程 ID。同样使用 jmx 方法,我们可以安排 jstack 在每个指定的时间间隔后重复执行。关于调用 Thread.getAllStackTraces(); 的第二点;这意味着我将手动记录线程转储,以使其被线程转储分析器解释。与您提到的第一种方法相比,这种方法有什么好处?
  • 我会在程序中使用分析器,并且只记录您感兴趣的信息。在我的情况下,这只发生在我遇到问题时,这通常意味着我想看看其他日志发生在什么地方时间,例如它发生在什么时间,线程记录的最后一件事是什么,之后产生的错误。
【解决方案3】:

如果有这样的环境,我建议您在暂存环境中进行所有堆分析,然后在生产环境中反映您所需的应用程序服务器调整(如果有)。如果您需要转储来分析应用程序的内存利用率,那么也许您应该考虑对其进行分析以进行更好的分析。

堆转储通常是由于OutOfMemoryExceptions 由内存泄漏和错误的内存管理引起的。

检查您的应用程序服务器的文档,大多数现代服务器都有在运行时生成转储的方法,除了我前面提到的正常原因之外,生成的转储可能是特定于供应商的。

【讨论】:

  • 我了解获取线程转储的开销,但要清楚了解生产环境中发生的情况,我们需要此功能。我们使用 glassfish 应用服务器,在 glassfish 中获取线程转储并没有什么特别之处。您需要向 jvm 发送终止信号,这在我对@Peter Lljenbery 的回复中提到了两个缺点。
  • 知道了,那么我建议您使用启用了内存转储的特殊构建(也许通过配置)并衡量您的评估内容,然后在完成后禁用它。这样,您就不必担心使用 jstack 或任何其他此类方法的含义。实际上,在这种情况下, jstack 就可以了。你也应该检查一下这个link,它可能会有所帮助(滚动到描述部分)。
  • 所以你推荐我上面描述的方法2?你对我上面提到的缺点有什么看法?另外你认为在生产环境中执行 runtime.exec() 会有什么问题吗?
  • 相反,我是说 jstack 会根据您的条件完成这项工作,我只是建议您在应用程序中添加一些方法,您可以通过这些方法按需触发这些转储,并拥有一个配置来禁用这个特性。你不想让它在生产中可用。
【解决方案4】:

如果它是*nix,我会尝试kill -3 &lt;PID&gt;,但你需要知道进程ID,也许你无权访问控制台?

【讨论】:

  • 是的。访问控制台和获取进程 ID 是“kill”方法的问题。我上面提到的方法没有这些缺点。
猜你喜欢
  • 1970-01-01
  • 2011-07-04
  • 2016-05-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-11
  • 1970-01-01
相关资源
最近更新 更多