eclipse内存分析器看到整个堆转储的小部分(363,2MB)(8GB)

时间:2013-06-13 11:07:35

标签: java garbage-collection heap-dump eclipse-memory-analyzer eclipse-mat

我正在尝试调查在tomcat中部署的Web应用程序的高负载下发生的java.lang.OutOfMemoryError: GC limit exceeded。堆大小设置为8GB(-Xms2048m -Xmx8192m

在某些时候,由于GC活动开销,我们的应用程序无响应。我可以在日志中看到Full GC连续多次出现。所以我使用以下命令(jmap -F -dump:format=b,file=/root/dump2.hprof 4963)进行堆转储。包含dump的文件大小为9GB。在转储(app被冻结约45分钟)后,发生了多个完整的GC,直到OutOfMemoryError被抛出。

以下是GC活动的对数样本

[Full GC [PSYoungGen: 932096K->875513K(1864128K)] [ParOldGen: 5592447K->5592447K(5592448K)] 6524543K->6467961K(7456576K) [PSPermGen: 112285K->112285K(262144K)], 12.3954040 secs] [Times: user=47.60 sys=0.43, real=12.39 secs]
[Full GC [PSYoungGen: 932096K->890562K(1864128K)] [ParOldGen: 5592447K->5592447K(5592448K)] 6524543K->6483009K(7456576K) [PSPermGen: 112285K->112285K(262144K)], 12.6131900 secs] [Times: user=48.45 sys=0.49, real=12.61 secs]
[Full GC [PSYoungGen: 932096K->895268K(1864128K)] [ParOldGen: 5592447K->5592447K(5592448K)] 6524543K->6487715K(7456576K) [PSPermGen: 112285K->112285K(262144K)], 12.9488670 secs] [Times: user=49.61 sys=0.46, real=12.95 secs]

Heap
 PSYoungGen      total 1864128K, used 896698K [0x0000000755560000, 0x0000000800000000, 0x0000000800000000)
  eden space 932096K, 96% used [0x0000000755560000,0x000000078c10e8a8,0x000000078e3a0000)
  from space 932032K, 0% used [0x000000078e3a0000,0x000000078e3a0000,0x00000007c71d0000)
  to   space 932032K, 0% used [0x00000007c71d0000,0x00000007c71d0000,0x0000000800000000)
ParOldGen       total 5592448K, used 5592447K [0x0000000600000000, 0x0000000755560000, 0x0000000755560000)
  object space 5592448K, 99% used [0x0000000600000000,0x000000075555ff30,0x0000000755560000)
PSPermGen       total 262144K, used 112285K [0x00000005e0000000, 0x00000005f0000000, 0x0000000600000000)
  object space 262144K, 42% used [0x00000005e0000000,0x00000005e6da7530,0x00000005f0000000)

heap dump is taken (ca 45minutes freeze)
[Full GC [PSYoungGen: 932096K->903362K(1864128K)] [ParOldGen: 5592447K->5592447K(5592448K)] 6524543K->6495810K(7456576K) [PSPermGen: 112285K->112285K(262144K)], 2883.9864390 secs] [Times: user=49.41 sys=0.47, real=2884.17 secs]
[Full GC [PSYoungGen: 932096K->897728K(1864128K)] [ParOldGen: 5592447K->5592444K(5592448K)] 6524543K->6490173K(7456576K) [PSPermGen: 112288K->112288K(262144K)], 13.3092680 secs] [Times: user=50.75 sys=0.40, real=13.31 secs]

为了分析堆转储我在eclipse内存分析器(MAT)中打开它。不幸的是,MAT显示堆大小为363.2MB(在概述选项卡或堆转储详细信息选项卡中),而根据GC日志堆填充为6467961K(6.4G)。无法到达的对象直方图总共显示75 511 736(75 MB)。直方图视图也证实总浅堆为380 837 136(363.2MB)

我的问题是,如果GC无法回收内存,MAT不会显示堆转储中的所有对象?

env details:
Eclipse Memory Analyzer Version 1.2.1
heap dump taken on
java version "1.7.0_13"
Java(TM) SE Runtime Environment (build 1.7.0_13-b20)
Java HotSpot(TM) 64-Bit Server VM (build 23.7-b01, mixed mode)

以下是MAT中导入的堆转储的屏幕截图:

5 个答案:

答案 0 :(得分:9)

默认情况下,MAT不会显示无法访问的对象。

您可以转到偏好设置 - >启用该选项。内存分析器 - >保持无法访问的对象。启用该选项后再次加载堆。

启用该选项后,它将显示完整的堆。 即使我处于相同的情况,也无法在线获取更多信息,我的经理向我展示了选项。希望它有所帮助。

答案 1 :(得分:0)

收集如此大堆的堆转储时,这是MAT的常用行为。我经常收集8GB堆的堆转储,通常会得到一个显示~1GB活动对象的MAT配置文件。

预计45分钟冻结。我的解释是在堆转储集合期间发生了几次 FullGC循环,这减少了获取的实际堆转储的大小。但我没有找到官方解释或参考文件记录为什么会有这么大的差异。

此外,请参阅此参考资料 - MAT Does Not Show the Complete Heap

  

症状:以交互方式监视内存使用情况时,使用的堆大小比MAT报告的大得多。

     

在索引创建期间,Memory Analyzer会删除无法访问的对象,因为各种垃圾收集器算法往往会留下一些垃圾(如果对象太小,移动并重新分配地址是昂贵的)。但是,这应该不超过3%到4%。如果您想知道删除了哪些对象,请按照此处的说明启用调试输出:MemoryAnalyzer/FAQ#Enable_Debug_Output

答案 2 :(得分:0)

实际上,我不建议您在解决java.lang.OutOfMemoryError: GC limit exceeded问题时使用jmap实用程序。我已经看到了这种方法的问题,而JVM正在捣乱(过多的主要集合)。

请尝试以下方法,看看你是否从MAT解析&分析过程:

  • 添加以下JVM HotSpot参数-XX:+ HeapDumpOnOutOfMemoryError
  • 再次复制问题并等待OOM事件。堆转储生成应该快得多,这将增加数据的价值和有效性。
  • 然后,JVM将在OOM事件之后生成JVM Heap Dump(HPROF格式)。
  • 再次在MAT中加载JVM堆转储,看看您是否获得了更好的结果,例如:更大的堆足迹。

此致 p-h

答案 3 :(得分:0)

我们最近在MAT中发现了一个错误,它只会看到堆的子集:https://bugs.eclipse.org/bugs/show_bug.cgi?id=404679#c3

问题是JVM编写了一条超过4GB的单个HEAP_DUMP记录,因此报头中的长度已被包装。

你在运行什么版本的MAT?请尝试更新的版本。

答案 4 :(得分:0)

默认情况下,MAT 会从其视图中隐藏所有无法访问的对象,因为这些对象已经被标记为垃圾收集。

可以在以下视图中访问无法访问的对象:

<块引用>
  1. 关闭快照
  2. 使用 Window > Heap Dump History 右键单击​​选择堆转储,删除索引文件
  3. 使用“窗口”>“首选项”>“内存分析器”选择“保留无法访问的对象”
  4. 重新打开堆转储,这将重新解析堆转储。
  5. 选择 Java Basics > GC Roots 查询。
  6. 选择“无法访问的对象”行。
  7. 对该行运行“显示保留集”查询。

这将显示通常情况下所有对象的直方图 无法访问,将在下一次机会被垃圾收集。作为 这些对象现在在快照中,然后可以在其中进行检查 更多细节。

有关详细信息,请参阅: Eclipse MAT Reference - Unreachable objects