Luk*_*zek 7 java garbage-collection heap-dump eclipse-mat eclipse-memory-analyzer
我试图调查java.lang.OutOfMemoryError: GC limit exceeded在tomcat中部署的Web应用程序的高负载下发生的情况.堆大小设置为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]
Run Code Online (Sandbox Code Playgroud)
为了分析堆转储我在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)
Run Code Online (Sandbox Code Playgroud)
以下是MAT中导入的堆转储的屏幕截图:
小智 10
默认情况下,MAT不显示无法访问的对象.
您可以通过转到首选项 - >内存分析器 - >保持无法访问的对象来启用该选项.启用该选项后再次加载堆.
一旦启用该选项,它将显示完整的堆.即使我处于相同的情况,也无法在线获取更多信息,我的经理向我展示了选项.希望它有所帮助.
这是MAT 在收集如此大堆的堆转储时的常见行为。我经常收集 8GB 堆的堆转储,并且通常会获得显示 ~1GB 活动对象的 MAT 配置文件。
45 分钟的冻结也在意料之中。我的解释是,在堆转储收集期间,会发生几个FullGC 周期,这会减少所获取的实际堆转储的大小。但我还没有找到官方解释或参考记录为什么会有这么大的差异。
此外,请参阅此参考文献 - MAT does Not Show the Complete Heap:
症状:以交互方式监视内存使用情况时,已使用的堆大小比 MAT 报告的大得多。
在索引创建期间,内存分析器会删除无法访问的对象,因为各种垃圾收集器算法往往会留下一些垃圾(如果对象太小,则移动和重新分配地址的成本会很高)。然而,这个比例不应超过 3% 至 4%。如果您想知道删除了哪些对象,请启用调试输出,如下所述:MemoryAnalyzer/FAQ#Enable_Debug_Output
| 归档时间: |
|
| 查看次数: |
5383 次 |
| 最近记录: |