Java内存溢出自动堆转储文件名称

25

我有多个Java进程,我正在尝试管理在发生OOM错误时创建的堆转储。当我说管理时,我的意思是:

  • 基于源进程不同命名堆转储
  • 删除旧的堆转储以保留磁盘空间

在发生OOM时进行堆转储。

 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp

JVM在指定的/tmp文件夹中创建一个名为java_pidXXXX.hprof的文件(其中XXXX是进程的PID)。是否有一种方法可以指定不同的格式,其中PID和DATE用于创建文件名?经过一小时的谷歌搜索,我尝试了myPrefix_$,{pid},'date'等。唯一有效的两个选项是:

  1. 不指定文件名,将获得java_pidXXXX.hprof
  2. 指定静态文件名,例如\tmp\OOM.hprof。

如果/tmp文件夹不存在,则不会创建它,也不会创建堆转储。唯一可行的想法是在OOM错误时添加一个命令。

-XX:OnOutOfMemoryError="doSomething.sh %p"

但我试图避免这样做,因为我需要部署“doSomething.sh”


1
为什么需要在文件名中包含日期?如果您想要删除旧文件,可以通过文件的修改时间来完成,不必在文件名中包含日期。 - RealSkeptic
2个回答

19
命令行中的-XX:HeapDumpPath不能比您已经发现的更加灵活。也就是说,您可以选择:
  • 设置目录名称,然后默认名称java_pidXXX.hprof将在该目录中创建。
  • 设置文件名称,那么该文件将按原样使用。
HotSpot源代码中相关的代码是heapDumper.cpp。阅读它时,它不会查找给定路径中的任何“魔法序列”:
  • 它检查给定路径是否是目录。如果是,则将其用作前缀,添加文件分隔符,并使用默认文件名。默认文件名由硬编码部分构建而成,使用的字符串格式不受您控制。
  • 如果不是目录,则直接使用它。
  • 如果这不是此JVM生命周期内的第一个转储,则还会附加序列号。
就是这样。没有对路径的解析,只是确定它是否为目录。
您唯一可以添加的灵活性是在构建命令行上的名称时使用shell的能力。这就是为什么您可能会在网络上看到一些示例,例如name_`date`.ext - 这是由shell处理的,它将`date`替换为当前日期一次。也就是说,文件名将始终具有shell处理命令并启动JVM时的日期/时间,而不是创建转储时的日期/时间。如果这对您足够好-您可以使用它。请注意,现在认为使用语法name_$(date).ext更可接受。

如果你只是想根据文件的最后修改时间来删除旧文件,那么可以使用Unix/Linux工具find来帮助你。不需要在名称中包含日期。

$(date)(或`date`)技巧不能帮助你获取PID。如果使用$$,shell也可以替换当前PID,但它是处理命令行的shell的PID,而不是JVM进程本身的PID。但是,如果你使用shell的exec命令启动JAVA应用程序,它将接收与其来源的shell相同的进程ID,因此你实际上可以使用$$来构建文件名。请记住,exec之后的脚本将不会执行。

因此,你可以尝试@apangin在他的回答中提到的文件名的动态更改方法。不过要注意的是,很难确定转储本身的时间,因为你希望在OOM发生之前设置好文件名。


1
如果我使用的 dumppath 是 "/var/data/heapdump.hprof",并且目录中已经存在一个 heapdump,那么会生成新的 heapdump 文件还是失败? - Manish

19

HeapDumpPath 是一个可管理的虚拟机选项。这意味着您可以在运行时使用 JMX 将其设置为任何您想要的值。

    String pid = ManagementFactory.getRuntimeMXBean().getName();
    pid = pid.substring(0, pid.indexOf('@'));
    String date = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
    String fileName = "/tmp/heap_" + pid + "_" + date + ".dump";

    HotSpotDiagnosticMXBean bean = ManagementFactory.newPlatformMXBeanProxy(
            ManagementFactory.getPlatformMBeanServer(),
            "com.sun.management:type=HotSpotDiagnostic",
            HotSpotDiagnosticMXBean.class);
    bean.setVMOption("HeapDumpOnOutOfMemoryError", "true");
    bean.setVMOption("HeapDumpPath", fileName);

我想知道如果在VM选项中启用HeapDumpGzipLevel会发生什么?HotSpot会自动调整我的自定义名称以为其添加.gz后缀吗?还是我需要手动处理它? - turbanoff

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接