Java垃圾收集器奇怪的行为

时间:2016-08-07 08:42:47

标签: java garbage-collection

我在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的行为如此吗?

1 个答案:

答案 0 :(得分:0)

我终于找到了原因。

当JVM尝试为对象分配堆时,它首先检查相应TLAB(线程本地分配缓冲区)的可用大小,如果它不够,则尝试增长它。 如果Eden空间的剩余大小不足以进行TLAB扩展,那么JVM会查找Eden空间本身。它的剩余大小Eden空间也不够,然后JVM直接在Old Gen空间中分配对象。

除此之外,如果NewGen尺寸较小,那么不仅Eden空间而且两个幸存者空间也都较小(通常为8或16倍)。因此,即使JVM设法在Eden空间中分配空间,如果这些对象能够在几个次要集合中存活下来。幸存者空间将溢出,并将移动到OldGen空间。