线程转储和内存转储仅在特定时间点有意义?

Thread dump and memory dump makes sense only at particular point of time?

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

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

我没有在 jconsole、jvisualvm 或 dynatrace 中看到任何执行此操作的方法。也许有办法,但我没有找到?

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

对于线程转储,您可以将 jstack, and jhat 用于堆转储。两者都是标准 JDK 的一部分。

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

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

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

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

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

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

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

所以你的问题可以由衷地回答:"It depends"。仅当您看到 OutOfMemoryErrors 时才应提取内存转储。线程转储在可能存在高流量/冻结/线程拥塞时很有用。

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

  1. jstat -gc Process_ID 300s

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

  1. jmap -histo Process_ID

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

如果#1 和#2 显示内存泄漏的症状,那么只进行堆转储,但它可能 "hang" 您的应用程序,您可能必须在捕获堆转储后立即重新启动它。

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

jstack Process_ID

或(Java 8)

jcmd Process_ID Thread.print

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

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