我在java GC中遇到了这种奇怪的行为。
我们有一个最大堆为1GB的应用程序,它导致GC开销限制超出错误。
下面是jmap -heap输出;
Heap Configuration: MinHeapFreeRatio = 40 MaxHeapFreeRatio = 70 MaxHeapSize = 1610612736 (1536.0MB) NewSize = 1572864 (1.5MB) MaxNewSize = 536870912 (512.0MB) OldSize = 1072168960 (1022.5MB) NewRatio = 2 SurvivorRatio = 8 MetaspaceSize = 21807104 (20.796875MB) CompressedClassSpaceSize = 1073741824 (1024.0MB) MaxMetaspaceSize = 17592186044415 MB G1HeapRegionSize = 0 (0.0MB)
Heap Usage:
PS Young Generation
Eden Space:
capacity = 37224448 (35.5MB)
used = 34328776 (32.73847198486328MB)
free = 2895672 (2.7615280151367188MB)
92.2210478446853% used
From Space:
capacity = 1572864 (1.5MB)
used = 786432 (0.75MB)
free = 786432 (0.75MB)
50.0% used
To Space:
capacity = 1572864 (1.5MB)
used = 0 (0.0MB)
free = 1572864 (1.5MB)
0.0% used
PS Old Generation
capacity = 1072168960 (1022.5MB)
used = 13918336 (13.2735595703125MB)
free = 1058250624 (1009.2264404296875MB)
1.2981476352383863% used
所以我们用以下参数调整了GC;
-XX:NewSize=512 -XX:MaxNewSize=512 -XX:SurvivorRatio=16 -XX:NewRatio=1
NewSize和MaxNewSize应该以MB为单位设置。
但是使用这种配置,我们得到以下堆映射。
Heap Configuration: MinHeapFreeRatio = 40 MaxHeapFreeRatio = 70 MaxHeapSize = 2147483648 (2048.0MB) NewSize = 1572864 (1.5MB) MaxNewSize = 1572864 (1.5MB) OldSize = 1072168960 (1022.5MB) NewRatio = 1 SurvivorRatio = 16 MetaspaceSize = 21807104 (20.796875MB) CompressedClassSpaceSize = 1073741824 (1024.0MB) MaxMetaspaceSize = 17592186044415 MB G1HeapRegionSize = 0 (0.0MB)
Heap Usage:
PS Young Generation
Eden Space:
capacity = 524288 (0.5MB)
used = 200200 (0.19092559814453125MB)
free = 324088 (0.30907440185546875MB)
38.18511962890625% used
From Space:
capacity = 524288 (0.5MB)
used = 98304 (0.09375MB)
free = 425984 (0.40625MB)
18.75% used
To Space:
capacity = 524288 (0.5MB)
used = 0 (0.0MB)
free = 524288 (0.5MB)
0.0% used
PS Old Generation
capacity = 1072168960 (1022.5MB)
used = 522704656 (498.49000549316406MB)
free = 549464304 (524.0099945068359MB)
48.752078776837564% used
现在伊甸园的空间容量只有0.5MB,但它只占38%,之前是92%,容量是35MB。 旧的Gen使用率增加了50%,之前约为2%。
有人可以解释为什么GC的行为如此吗?
答案 0 :(得分:0)
我终于找到了原因。
当JVM尝试为对象分配堆时,它首先检查相应TLAB(线程本地分配缓冲区)的可用大小,如果它不够,则尝试增长它。 如果Eden空间的剩余大小不足以进行TLAB扩展,那么JVM会查找Eden空间本身。它的剩余大小Eden空间也不够,然后JVM直接在Old Gen空间中分配对象。
除此之外,如果NewGen尺寸较小,那么不仅Eden空间而且两个幸存者空间也都较小(通常为8或16倍)。因此,即使JVM设法在Eden空间中分配空间,如果这些对象能够在几个次要集合中存活下来。幸存者空间将溢出,并将移动到OldGen空间。