Java 内存不足自动堆转储文件名
Java Out of memory automatic heap dump file name
我有几个 Java 进程,我正在尝试管理发生 OOM 错误时创建的堆转储。当我说管理时,我的意思是
- 根据原始进程以不同方式命名堆转储
- 删除旧的堆转储以保留磁盘 space
当使用
在 OOM 上转储堆时
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp
JVM 在指定的 /tmp 文件夹中创建一个具有以下名称 java_pidXXXX.hprof 的文件(其中 XXXX 是进程的 PID)。
无论如何指定使用 PID 和 DATE 来创建文件名的不同格式?
谷歌搜索一个小时后,我尝试了 myPrefix_$、{pid}、'date'..等。
唯一有效的两件事是
- 不指定文件名,你会得到 java_pidXXXX.hprof
- 指定静态文件名,例如\tmp\OOM.hprof.
如果 \tmp 文件夹不存在,则不会创建它,也不会创建堆转储。
可以使用的一个想法是在 OOM 错误上添加一个命令
-XX:OnOutOfMemoryError="doSomething.sh %p"
但我试图避免它,因为我需要部署 "doSomething.sh"
HeapDumpPath
是一个易于管理的 VM 选项。这意味着您可以使用 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);
命令行上的 -XX:HeapDumpPath
并没有比您已经发现的更灵活。也就是说,您可以:
- 设置一个目录名称,然后默认名称
java_pidXXX.hprof
将在该目录中创建。
- 设置一个文件名,该文件将按原样使用。
HotSpot源码中的相关代码为heapDumper.cpp。读取它时,它不会在给定路径内查找任何 "magic sequences":
- 它检查给定的路径是否是一个目录。如果是这样,使用它作为前缀,添加文件分隔符,并使用默认文件名,该文件名由使用不受您控制的字符串格式的硬编码部分组成。
- 如果它不是一个目录,它就按原样使用它。
- 如果它不是此 JVM 生命周期中的第一个转储,它还会附加一个序列号。
就是这样。除了确定它是否是目录之外,不解析路径。
唯一可以增加的灵活性是在命令行上构造名称时使用 shell 的功能。这就是为什么您可能会在网络上看到一些使用类似 name_`date`.ext
的示例 - 这是由 shell 处理的,它将 `date`
替换为当前日期 once。也就是说,当 shell 处理命令并启动 JVM 时,文件名将始终具有 date/time - 而不是创建转储时的 date/time 。如果这对你来说足够好 - 你可以使用它。请注意,现在人们认为使用语法 name_$(date).ext
.
更容易接受
如果您只需要日期就可以删除旧文件,那么您可以根据文件的最后修改时间删除它们(Unix/Linux 实用程序 find
可以帮助您).名称中不需要包含日期。
$(date)
(或`date`
)技巧对 PID 没有帮助。如果您使用 $$
,shell 也可以替换当前 PID - 但处理命令行 的是 shell 的 PID,而不是JVM 进程本身。但是,如果您使用 shell exec
命令启动您的 JAVA 应用程序,它会收到与它起源的 shell 相同的进程 ID,因此您实际上可以使用 $$
来建立你的文件名。请记住,exec
之后的任何内容都不会从您的脚本中执行。
所以你可以试试@apangin 在他的回答中建议的动态更改文件名。但请注意,确定转储本身的时间可能有点困难,因为您希望在 OOM 实际发生之前设置文件名。
我有几个 Java 进程,我正在尝试管理发生 OOM 错误时创建的堆转储。当我说管理时,我的意思是
- 根据原始进程以不同方式命名堆转储
- 删除旧的堆转储以保留磁盘 space
当使用
在 OOM 上转储堆时 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp
JVM 在指定的 /tmp 文件夹中创建一个具有以下名称 java_pidXXXX.hprof 的文件(其中 XXXX 是进程的 PID)。 无论如何指定使用 PID 和 DATE 来创建文件名的不同格式? 谷歌搜索一个小时后,我尝试了 myPrefix_$、{pid}、'date'..等。 唯一有效的两件事是
- 不指定文件名,你会得到 java_pidXXXX.hprof
- 指定静态文件名,例如\tmp\OOM.hprof.
如果 \tmp 文件夹不存在,则不会创建它,也不会创建堆转储。
可以使用的一个想法是在 OOM 错误上添加一个命令
-XX:OnOutOfMemoryError="doSomething.sh %p"
但我试图避免它,因为我需要部署 "doSomething.sh"
HeapDumpPath
是一个易于管理的 VM 选项。这意味着您可以使用 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);
命令行上的 -XX:HeapDumpPath
并没有比您已经发现的更灵活。也就是说,您可以:
- 设置一个目录名称,然后默认名称
java_pidXXX.hprof
将在该目录中创建。 - 设置一个文件名,该文件将按原样使用。
HotSpot源码中的相关代码为heapDumper.cpp。读取它时,它不会在给定路径内查找任何 "magic sequences":
- 它检查给定的路径是否是一个目录。如果是这样,使用它作为前缀,添加文件分隔符,并使用默认文件名,该文件名由使用不受您控制的字符串格式的硬编码部分组成。
- 如果它不是一个目录,它就按原样使用它。
- 如果它不是此 JVM 生命周期中的第一个转储,它还会附加一个序列号。
就是这样。除了确定它是否是目录之外,不解析路径。
唯一可以增加的灵活性是在命令行上构造名称时使用 shell 的功能。这就是为什么您可能会在网络上看到一些使用类似 name_`date`.ext
的示例 - 这是由 shell 处理的,它将 `date`
替换为当前日期 once。也就是说,当 shell 处理命令并启动 JVM 时,文件名将始终具有 date/time - 而不是创建转储时的 date/time 。如果这对你来说足够好 - 你可以使用它。请注意,现在人们认为使用语法 name_$(date).ext
.
如果您只需要日期就可以删除旧文件,那么您可以根据文件的最后修改时间删除它们(Unix/Linux 实用程序 find
可以帮助您).名称中不需要包含日期。
$(date)
(或`date`
)技巧对 PID 没有帮助。如果您使用 $$
,shell 也可以替换当前 PID - 但处理命令行 的是 shell 的 PID,而不是JVM 进程本身。但是,如果您使用 shell exec
命令启动您的 JAVA 应用程序,它会收到与它起源的 shell 相同的进程 ID,因此您实际上可以使用 $$
来建立你的文件名。请记住,exec
之后的任何内容都不会从您的脚本中执行。
所以你可以试试@apangin 在他的回答中建议的动态更改文件名。但请注意,确定转储本身的时间可能有点困难,因为您希望在 OOM 实际发生之前设置文件名。