【问题标题】:Thread dump and memory dump makes sense only at particular point of time?线程转储和内存转储仅在特定时间点有意义?
【发布时间】:2015-12-10 12:57:11
【问题描述】:

根据我的理解,Java 线程转储是所有线程的转储,描述 JVM 中的每个线程正在做什么或每个线程的状态 在特定的时间点。同样,内存转储表示特定时间点内存的健康状况。

是否有任何工具提供一种方法来获取一个小时或更长时间的内存或线程转储,以便如果我想分析一个小时的状态,我可以这样做?

我在 jconsole、jvisualvm 或 dynatrace 中看不到任何方法。也许有办法,但我没有找到?

【问题讨论】:

  • 你想提取什么样的状态?
  • 我会说你不能有一个小时的“状态”......你可以有一个(非常长的)序列状态,每次(几乎)发生任何变化时都会将不同的状态添加到列表中。
  • 这可能有助于解释您要解决的问题

标签: java performance debugging thread-dump memory-dump


【解决方案1】:

至于内存转储:定期转储内存需要一个非常非常大且非常非常快的文件系统。所以不,我不建议这样做。最好根据 gc 活动或其他条件定义一些触发器。

关于堆栈跟踪:如果您面临竞争条件,即您的(大量多线程?)应用程序对所有用户冻结或减慢的阶段,我发现收集一些 (3-5) 线程转储很有帮助定期偏移 3 到 5 秒(我们从 5 分钟开始,随着系统变得更加稳定,将其缩短到 30m),然后将这些快照相互比较,以确定可能的干扰。

虽然第一次迭代涉及 jstack,但后来演变为基于 JMX 的对 Java 应用程序的访问并同时提取数据库锁定信息。

所以你的问题可以用衷心的方式回答:“这取决于”。仅当您看到 OutOfMemoryErrors 时才应提取内存转储。在可能存在高流量/冻结/线程拥塞的情况下,线程转储可能很有用。

【讨论】:

  • 虽然您不能进行连续的内存转储,但内存分析工具通常能够计算两个堆转储之间的增量,例如相隔一小时。
  • @biziclop 也许您可以就可以做到这一点的工具提出建议?对我来说,到目前为止,OutOfMemory 的分析已经奏效,所以我没有这些经验。
  • @Jan when you sa , I've found it helpful to collect a few (3-5) thread dumps with 3 to 5 seconds offset in regular intervals (we started off with 5 min and as system grew more stable cut it down to 30m) and then compare 这是否意味着您在不同的时间点服用了 3-4 次 dumpa。对吧?
  • @Jan jstack 也可以拉取数据库死锁信息吗?
  • @Jan 我不想这样做,因为每个工具的执行方式都略有不同。但是 visualvm 和 MAT 都可以。
【解决方案2】:

如果您想要定期转储内存/线程状态,我不知道有什么工具可以做到这一点,但编写自己的实现应该很容易。

对于线程转储,您可以使用jstackjhat 进行堆转储。两者都是标准 JDK 的一部分。

请记住,保存大量堆转储很容易耗尽所有磁盘内存。另外,我不确定长时间的线程转储是否有用。据我所知,它们通常用于在特定时间范围内检查堆栈以发现错误/死锁等。

【讨论】:

  • 我同意你的说法As far as I know they are often used to inspect the stacks at a specific time frame to find errors / deadlocks etc内存转储也是这样吗?
  • 内存(堆)转储通常用于调查内存泄漏。我经常使用VM自动生成的hprofs,一旦出现内存不足的错误(可以打开这个选项)来查找泄漏。
【解决方案3】:

您可以使用 Javamelody,但您需要将它“添加”到您的应用程序中。

https://github.com/javamelody/javamelody/

它允许您监视您的应用程序并查看历史记录,以及生成转储(但我认为它不能在过去的两个事件之间为您提供转储)

【讨论】:

    【解决方案4】:

    如果您想要完整的内存转储,那么您必须进行堆转储(jmap -F -dump:live,format=b,file=),这在生产系统中不推荐(Jan 已经指出)。但是,还有其他方法可以在不影响生产系统性能的情况下定期监控内存使用情况:

    1. jstat -gc Process_ID 300s

    这将每五分钟捕获一次总体内存使用情况和垃圾收集详细信息。但是,它不会告诉您哪个对象正在消耗多少内存等(由堆转储捕获)。但是,如果存在内存泄漏,您将能够随着时间的推移找出答案。

    1. jmap -histo Process_ID

    这将为应用程序生成直方图信息。编写一个脚本,每 _ 分钟调用一次。

    如果 #1 和 #2 显示内存泄漏的症状,则只进行堆转储,但它可能会“挂起”您的应用程序,您可能必须在捕获堆转储后重新启动它。

    就线程转储而言,如果要定期监控线程状态,可以使用以下方法。我熟悉他们每 5 分钟执行一次并存储过去 7 天数据的应用程序。

    jstack Process_ID

    或(使用 Java 8)

    jcmd Process_ID Thread.print

    在异常情况下,您始终可以每 10 秒捕获 5/6 个线程转储。

    或者,如果您(或您的公司)负担得起并且想要定期关注系统,您可能会寻找New Relic 之类的软件。

    【讨论】:

      猜你喜欢
      • 2016-10-09
      • 2013-12-11
      • 1970-01-01
      • 2016-12-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多