【问题标题】:Java : Get heap dump without jmap or without hanging the applicationJava:在没有 jmap 或不挂起应用程序的情况下获取堆转储
【发布时间】:2014-01-16 22:34:12
【问题描述】:

在少数情况下,我们的应用程序使用了大约 12 GB 的内存。 我们尝试使用 jmap 实用程序获取堆转储。由于应用程序使用了一些 GB 的内存,它会导致应用程序停止响应并导致生产出现问题。

在我们的案例中,堆使用量在 6 小时内突然从 2-3 GB 增加到 12 GB。为了找到内存使用趋势,我们尝试在重新启动应用程序后每隔一小时收集一次堆转储。但是如前所述,由于使用 jmap 导致应用程序挂起,我们需要重新启动它,我们无法获得内存使用的趋势。

有没有办法在不挂起应用程序的情况下获取堆转储,或者是否有除 jmap 之外的实用程序来收集堆转储。

对此的想法非常感谢,因为如果不了解内存使用趋势,则很难解决此问题。

注意:我们的应用程序在 CentOS 中运行。

谢谢, 阿伦

【问题讨论】:

    标签: java memory heap-memory jmap


    【解决方案1】:

    试试下面的。它带有 JDK >= 7:

    /usr/lib/jvm/jdk-YOUR-VERSION/bin/jcmd PID GC.heap_dump FILE-PATH-TO-SAVE
    

    例子:

    /usr/lib/jvm/jdk1.8.0_91/bin/jcmd 25092 GC.heap_dump /opt/hd/3-19.11-jcmd.hprof
    

    这个转储过程比用 jmap 转储快得多!转储文件要小得多,但足以让您了解泄漏的位置。

    在撰写此答案时,Memory Analyzer 和 IBM HeapAnalyzer 存在错误,它们无法从 jmap(jdk8、大文件)读取转储文件。您可以使用 Yourkit 读取这些文件。

    【讨论】:

      【解决方案2】:

      首先,在拍摄线程转储/快照时冻结 JVM 是(AFAIK)必不可少的。如果 JVM 在创建快照时能够继续运行,那么几乎不可能获得一致的快照。

      那么还有其他方法可以获得堆转储吗?

      • 您可以使用 VisualVM 获取堆转储,如 here 所述。

      • 您可以使用 jconsole 或 Eclipse 内存分析器获取堆转储,如 here 所述。

      但所有这些都必然会导致 JVM(至少)暂停。


      如果您的应用程序实际上挂起(永久!),这听起来像是您的应用程序本身的问题。我的建议是在查找存储泄漏之前,看看您是否可以找到那个问题。

      我的另一个建议是查看单个堆转储,并使用统计信息来确定哪些类型的对象正在使用所有空间......以及为什么它们可以访问。您很有可能根本不需要“趋势”信息。

      【讨论】:

      • 感谢斯蒂芬。您是否建议使用直方图?
      • @Arun - 我建议您进行一次堆转储,并使用可用工具 1) 识别最大、最常见或最可疑的对象类型,然后 2) 找出如何/为什么可以访问它们。这是在 Java 中查找存储泄漏的正常方法。
      【解决方案3】:

      您可以使用 GDB 获取堆转储,而无需在目标 VM 上运行 jmap,但这仍会在将堆转储写入磁盘所需的时间内挂起应用程序。假设磁盘速度为 100MB/s(基本镜像阵列或单个磁盘),这仍然是 2 分钟的停机时间。 http://blogs.atlassian.com/2013/03/so-you-want-your-jvms-heap/

      避免停止 JVM 的唯一真正方法是事务内存和利用它提供进程快照功能的内核。这是 STM 支持者的梦想之一,但目前尚不可用。 VMWare 的热迁移接近但取决于您的分配率不超过网络带宽并且它不保存快照。请他们为您添加它,这将是一个很好的功能。

      【讨论】:

        【解决方案4】:

        使用正确的工具分析的堆转储会告诉您究竟是什么在消耗堆。它是追踪内存泄漏的最佳工具。但是,收集堆转储很慢,更不用说分析了。

        了解您的应用程序的工作原理后,有时直方图就足以为您提供在哪里寻找问题的线索。例如,如果MyClass$Inner 位于直方图的顶部,而MyClass$Inner 仅在MyClass 中使用,那么您确切知道要查找哪个文件。

        这是收集直方图的命令。

        jcmdpidGC.class_histogram filename=histogram.txt

        【讨论】:

          【解决方案5】:

          要补充斯蒂芬的答案,您还可以通过 API 触发堆转储以用于最常见的 JVM 实现:

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2015-07-10
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-05-15
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多