Java HeapDumps 表明在 OutOfMemory 异常后使用的堆大小比实际堆定义小 30%

Java HeapDumps indicate that used Heap Size is 30% smaller than actual heap definition after OutOfMemory exceptions

在 JVM 抛出 OutOfMemory 异常后,我正在分析一些堆转储。我在 Windows 2008R2 平台上使用 Hotspot JDK 1.7(64 位)。应用服务器是 JBoss 4.2.1GA,通过 Tanuki Java Service Wrapper.

启动

它使用以下参数启动:

wrapper.java.additional.2=-XX:MaxPermSize=256m
wrapper.java.initmemory=1498
wrapper.java.maxmemory=3000
wrapper.java.additional.19=-XX:+HeapDumpOnOutOfMemoryError

转换为:

-Xms1498m -Xmx3000m -XX:MaxPermSize=256m -XX:+HeapDumpOnOutOfMemoryError

还有一些其他的 GC 和 JMX 配置参数。

我的问题是,当我使用 Eclipse Memory Analyzer 分析由于 OutOfMemoryException 创建的堆转储时,MAT 始终显示堆大小为 2.3G 或 2.4G。我已经将 MAT 中的选项启用为 Keep Unreachable Objects,所以我不相信 MAT 正在修剪堆。

java.lang.RuntimeException: java.lang.OutOfMemoryError: GC overhead limit exceeded

java.lang.OutOfMemoryError: Java heap space

MAT 中的总结:

Size: 2.3 GB Classes: 21.7k Objects: 47.6m Class Loader: 5.2k

我的实际堆文件大小大约是 3300KB,所以它们符合我的 3000m 最大堆大小设置。

那么MAT中缺失的500-600M内存在哪里呢?为什么 MAT 只显示我的堆大小为 2.4G?

SO 上的其他帖子倾向于表明是 JVM 在转储堆之前执行了一些 GC,但是如果丢失的 500M 是由于 GC,为什么它甚至首先抛出 OOM?如果 GC 实际上可以清理 500M(或我的堆的近 25%),那么 JVM 真的内存不足吗?

有没有办法调整堆转储以便我可以获得堆的 full/complete 图片(包括丢失的 500M)?

如果没有,我发现我真的很难找到 how/why 我首先遇到了这些 OOM。

应某人的要求,我附上了来自活动节点的 jstat -gc <PID> 1000 的输出:http://pastebin.com/07KMG1tr.

您使用的是哪个 GC? 你可能错过了 Eden,尝试使用 jstat - Java Virtual Machine Statistics Monitoring Tool

java.lang.OutOfMemoryError: GC overhead limit exceeded

这并不一定意味着您的堆已满,请参阅 this Q&A

java.lang.OutOfMemoryError: Java heap space

这并不意味着您的堆剩余 0 字节,这意味着无法满足分配请求。如果有东西试图分配 600MB 而只剩下 500MB 那么这将引发 OOME。

If not, I find I'm really struggling to find how/why I'm encountering these OOMs in the first place.

获取堆栈跟踪以查看执行相关分配的调用站点是否有任何可疑行为将是一个开始。或者您可以尝试增加堆大小,看看问题是否消失。