javacore 和 heapdump 中的堆大小:IBM JVM 上的 20 倍差异

Heapsize in javacore and heapdump: 20x difference on IBM JVM

注意到生产服务器(Websphere8.5.5)开始消耗大量内存。

javacore 转储中的数字清楚地表明罪魁祸首是过大的堆:

|  +--Memory Manager (GC): 5,496,900,272 bytes / 3193 allocations
|  |  |
|  |  +--Java Heap: 5,368,770,560 bytes / 1 allocation
|  |  |
|  |  +--Other: 128,129,712 bytes / 3192 allocations  

但与此同时,在 MAT 中打开的堆转储报告堆的总体积约为 200M(有时高达 300M,但绝不会更多)。

这到底是什么意思?堆转储值得信赖吗?如果是,有没有办法释放未使用的堆内存?

更新:完整的 NATIVEMEM 部分,按要求

1MEMUSER       JRE: 7,211,791,256 bytes / 39196 allocations
1MEMUSER       |
2MEMUSER       +--VM: 6,772,051,048 bytes / 29934 allocations
2MEMUSER       |  |
3MEMUSER       |  +--Classes: 370,339,176 bytes / 10002 allocations
3MEMUSER       |  |  |
4MEMUSER       |  |  +--Shared Class Cache: 62,914,560 bytes / 1 allocation
3MEMUSER       |  |  |
4MEMUSER       |  |  +--Other: 307,424,616 bytes / 10001 allocations
2MEMUSER       |  |
3MEMUSER       |  +--Memory Manager (GC): 5,496,900,272 bytes / 3193 allocations
3MEMUSER       |  |  |
4MEMUSER       |  |  +--Java Heap: 5,368,770,560 bytes / 1 allocation
3MEMUSER       |  |  |
4MEMUSER       |  |  +--Other: 128,129,712 bytes / 3192 allocations
2MEMUSER       |  |
3MEMUSER       |  +--Threads: 91,710,312 bytes / 3408 allocations
3MEMUSER       |  |  |
4MEMUSER       |  |  +--Java Stack: 5,958,456 bytes / 349 allocations
3MEMUSER       |  |  |
4MEMUSER       |  |  +--Native Stack: 68,812,800 bytes / 248 allocations
3MEMUSER       |  |  |
4MEMUSER       |  |  +--Other: 16,939,056 bytes / 2811 allocations
2MEMUSER       |  |
3MEMUSER       |  +--Trace: 3,415,376 bytes / 1229 allocations
2MEMUSER       |  |
3MEMUSER       |  +--JVMTI: 17,776 bytes / 13 allocations
2MEMUSER       |  |
3MEMUSER       |  +--JNI: 5,821,768 bytes / 9844 allocations
2MEMUSER       |  |
3MEMUSER       |  +--Port Library: 794,750,560 bytes / 401 allocations
3MEMUSER       |  |  |
4MEMUSER       |  |  +--Unused <32bit allocation regions: 794,704,552 bytes / 87 allocations
3MEMUSER       |  |  |
4MEMUSER       |  |  +--Other: 46,008 bytes / 314 allocations
2MEMUSER       |  |
3MEMUSER       |  +--Other: 9,095,808 bytes / 1844 allocations
1MEMUSER       |
2MEMUSER       +--JIT: 436,874,280 bytes / 8850 allocations
2MEMUSER       |  |
3MEMUSER       |  +--JIT Code Cache: 268,435,456 bytes / 1 allocation
2MEMUSER       |  |
3MEMUSER       |  +--JIT Data Cache: 48,235,968 bytes / 23 allocations
2MEMUSER       |  |
3MEMUSER       |  +--Other: 120,202,856 bytes / 8826 allocations
1MEMUSER       |
2MEMUSER       +--Class Libraries: 2,865,928 bytes / 412 allocations
2MEMUSER       |  |
3MEMUSER       |  +--Harmony Class Libraries: 2,000 bytes / 1 allocation
2MEMUSER       |  |
3MEMUSER       |  +--VM Class Libraries: 2,863,928 bytes / 411 allocations
3MEMUSER       |  |  |
4MEMUSER       |  |  +--sun.misc.Unsafe: 2,635,720 bytes / 307 allocations
4MEMUSER       |  |  |  |
5MEMUSER       |  |  |  +--Direct Byte Buffers: 2,625,112 bytes / 304 allocations
4MEMUSER       |  |  |  |
5MEMUSER       |  |  |  +--Other: 10,608 bytes / 3 allocations
3MEMUSER       |  |  |
4MEMUSER       |  |  +--Other: 228,208 bytes / 104 allocations

NATIVEMEMINFO 部分显示了虚拟内存,因此 5,368,770,560 只是意味着 JVM 已经虚拟地为堆分配了那么多内存。实际驻留多少取决于实际堆大小和堆使用情况。例如,如果在 tenured region 中堆积了大量垃圾,然后在 full GC 中被清理,那么这些页面可能在某个时候成为常驻页面,但实际有多少是活跃的取决于许多因素。我相信当 JVM 启动时,它实际上分配了 -Xmx 的全部大小,所以我认为您总是会在 NATIVEMEMINFO 中看到堆的全部大小(也可能是它只分配 -Xms,因此,如果您看到的大于 -Xms,则意味着压力导致堆增加 [当然,请注意正常的 sawtooth])。

当您在 MAT 中加载转储时,它会运行完整的垃圾收集并默认从主视图中删除所有无法访问的对象。您可以单击 Overview 页面上的 "Unreachable Objects Histogram" link 并滚动到底部的 sum of shallow heap totals 行以查看 heapdump 中有多少 "trash"。 MAT 首选项中还有一个选项 "Keep unreachable objects" 可以将所有这些对象保留在主 MAT 视图中,但这通常不是很有用。

所以基本的答案是 MAT 只显示活动对象,所以在转储时,有 200-300MB 的活动对象。其余的可能在垃圾箱中,或者根本不存在,NATIVEMEMINFO 只是显示虚拟大小。

随着时间的推移查看堆使用情况的更好方法是 verbosegc 和加载 GCMV:

-Xverbosegclog:verbosegc.%seq.log,20,50000