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

Java eclipse内存分析器看到整个堆转储(8GB)的一小部分(363,2MB),java,garbage-collection,heap-dump,eclipse-memory-analyzer,eclipse-mat,Java,Garbage Collection,Heap Dump,Eclipse Memory Analyzer,Eclipse Mat,我试图调查java.lang.OutOfMemoryError:GC限制超过了,这是在tomcat中部署的web应用程序高负载时发生的。堆大小设置为8GB(-Xms2048m-Xmx8192m) 在某个时间点,由于GC活动开销,我们的应用程序变得没有响应。我可以在日志中看到完整GC在一行中多次出现。因此,我使用以下命令进行堆转储(jmap-F-dump:format=b,file=/root/dump2.hprof 4963)。包含转储的文件大小为9GB。转储完成后(应用程序被冻结约45分钟),

我试图调查
java.lang.OutOfMemoryError:GC限制超过了
,这是在tomcat中部署的web应用程序高负载时发生的。堆大小设置为8GB(
-Xms2048m-Xmx8192m

在某个时间点,由于GC活动开销,我们的应用程序变得没有响应。我可以在日志中看到完整GC在一行中多次出现。因此,我使用以下命令进行堆转储(
jmap-F-dump:format=b,file=/root/dump2.hprof 4963
)。包含转储的文件大小为9GB。转储完成后(应用程序被冻结约45分钟),发生多个完整的GCs,直到抛出
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(在overview选项卡或heap dump details选项卡中),而根据GC日志,堆的填充量高达6467961K(6.4G)。“无法访问对象”直方图显示的对象总数为75511736(75MB)。直方图视图也证实了总浅堆为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中导入堆转储的屏幕截图:


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

预计还将有45分钟的冻结。我的解释是,在堆转储收集期间会发生几个FullGC循环,这会减小实际获取的堆转储的大小。但我还没有找到官方解释或参考文件来说明为什么会有如此大的差异

此外,请参阅此参考-:

症状:当以交互方式监视内存使用情况时,使用的堆大小远远大于MAT报告的大小

在索引创建过程中,内存分析器会删除无法访问的对象,因为各种垃圾回收器算法往往会留下一些垃圾(如果对象太小,移动和重新分配地址的代价会很高)。然而,这不应超过3%至4%。如果您想知道删除了哪些对象,请启用调试输出,如下所述:


实际上,我不建议您在故障排除时使用jmap实用程序。在JVM破坏(过多的主要集合)时,我发现这种方法存在问题

请尝试以下方法,看看MAT解析和分析过程是否能获得更好的结果:

  • 添加以下JVM热点参数-XX:+HeapDumpOnOutOfMemoryError
  • 再次复制问题并等待OOM事件。堆转储的生成应该快得多,这将增加数据的价值和有效性
  • JVM随后将在OOM事件之后生成一个(HPROF格式)
  • 在MAT中再次加载JVM堆转储,并查看是否获得更好的结果,例如更大的堆占用空间
问候,,
默认情况下,P-H

MAT不会显示无法访问的对象

您可以通过进入“首选项->内存分析器->保留无法访问的对象”来启用该选项。启用该选项后,再次加载堆

启用该选项后,它将显示完整的堆。
就连我也处于同样的情况,无法在线获取太多信息,我的经理向我展示了这个选项。希望能有所帮助。

我们最近在MAT中发现了一个bug,它只能看到堆的一个子集:

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


您正在运行什么版本的MAT?请尝试较新的生成。

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

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

  • 关闭快照
  • 使用窗口>堆转储历史记录选择堆转储右键单击,删除索引文件
  • 使用窗口>首选项>内存分析器选择“保留无法访问的对象”
  • 重新打开堆转储,这将重新分析堆转储
  • 选择JavaBasics>GC根查询
  • 选择“无法访问的对象”行
  • 对该行运行“显示保留集”查询
  • 这将显示所有对象的直方图,这些对象通常是 无法访问,将在下一次机会时被垃圾收集。作为 这些对象现在位于快照中,然后可以在其中进行检查 更多细节

    有关详细信息,请参阅:

    好建议。这也帮助我发现了Apache PoII中的错误。我遇到了这样一种情况:我们使用了上面的标志-XX:+HeapDumpOnAutoFMMemoryError来生成堆转储,而当我们遇到java.lang.OutOfMemoryError时,它没有生成堆转储:GC限制超出了问题,因为继续触发GC调用以释放内存,并且它提高了CPU使用率服务器没有响应,因此服务器在触发堆转储之前崩溃。当内存使用率超过98%时,必须使用jmap实用程序并获取堆转储,这并没有真正让我们在OOM时获取准确的快照