G1 GC 分配的内存大于堆大小

G1 GC allocated memory is more than heap size

我为应用程序服务器更改了 GC。现在我使用 G1 GC。我有 30 GB 内存。对于初始测试,我仅将 Xms 和 Xmx 值设置为相同 23040 mb.

我使用的设置:

 -Xms23040m -Xmx23040m  -XX:+UseG1GC -XX:MetaspaceSize=512M -XX:MaxMetaspaceSize=1536m 

如果我使用 G1 GC,我会有有趣的 GCEasy 指标。

   Generation         | Allocated | Peak
   Young Gen          | 13.38     | 3.37
   Old Gen            | 21.17     | 485mb
   Meta Space         | 1.5       | n/a
   Young + old + Meta | 23.78     | 13.61

总计 36.05 GB 怎么得来的? GCEasy 图 link is here.

我不明白为什么分配的内存大于最大堆大小?

GC初始日志:

OpenJDK 64-Bit Server VM (25.282-b08) for linux-amd64 JRE (1.8.0_282-b08), built on Jan 20 2021 11:56:52 by "jenkins" with gcc 7.5.0
Memory: 4k page, physical 31389860k(23816948k free), swap 0k(0k free)
CommandLine flags: -XX:GCLogFileSize=3145728 -XX:InitialHeapSize=23923261440 -XX:MaxHeapSize=23923261440 -XX:MaxMetaspaceSize=1610612736 -XX:MetaspaceSize=536870912 -XX:NumberOfGCLogFiles=5 -XX:+PrintGC -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:-TraceClassUnloading -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseG1GC -XX:+UseGCLogFileRotation

GC 暂停日志:

    2022-01-19T08:18:40.340-0500: 45739.624: [GC pause (G1 Evacuation Pause) (young), 0.0675291 secs]
   [Parallel Time: 42.0 ms, GC Workers: 1]
      [GC Worker Start (ms):  45739624.2]
      [Ext Root Scanning (ms):  10.8]
      [Update RS (ms):  5.1]
         [Processed Buffers:  76]
      [Scan RS (ms):  2.1]
      [Code Root Scanning (ms):  2.9]
      [Object Copy (ms):  21.0]
      [Termination (ms):  0.0]
         [Termination Attempts:  1]
      [GC Worker Other (ms):  0.0]
      [GC Worker Total (ms):  41.9]
      [GC Worker End (ms):  45739666.1]
   [Code Root Fixup: 0.0 ms]
   [Code Root Purge: 0.0 ms]
   [Clear CT: 5.8 ms]
   [Other: 19.7 ms]
      [Choose CSet: 0.0 ms]
      [Ref Proc: 16.8 ms]
      [Ref Enq: 0.1 ms]
      [Redirty Cards: 0.1 ms]
      [Humongous Register: 0.1 ms]
      [Humongous Reclaim: 0.0 ms]
      [Free CSet: 2.3 ms]
   [Eden: 13632.0M(13632.0M)->0.0B(13632.0M) Survivors: 57344.0K->57344.0K Heap: 13933.2M(22816.0M)->307.2M(22816.0M)]
 [Times: user=0.07 sys=0.00, real=0.07 secs] 

这是否意味着 GCEasy.io 存在无法显示正确指标的错误?当我使用 Parallel GC 时,我没有遇到类似的问题。 (分配的内存比 Xmx 多)

table 中列出的分配大小包括 Metaspace。元空间是与 java 对象堆分开的内存池。因此堆和元空间的总和可以超过最大堆大小。

 [Eden: 13632.0M(13632.0M)->0.0B(13632.0M) Survivors: 57344.0K->57344.0K Heap: 13933.2M(22816.0M)->307.2M(22816.0M)]

这表明总体堆大小(所有代)为 ~22GB,在最大堆限制内。也许 gceasy 将总堆大小误认为是老年代?

这是你的JVM参数,数字是byte。 23923261440(字节)= 22815(Mb)= 22.28(Gb)

-XX:InitialHeapSize=23923261440
-XX:MaxHeapSize=23923261440

默认情况下,G1的Young GenOld Gen的space不是fixed.From您分享的GCEasy页面的Interactive Graphs栏, 我将以下信息整理成时间线。

GC Times Young Gen(Mb) Old Gen(Mb) Total(Mb)
First 1232 21584 22816
Fifth 1136 21680 22816
33th 5384 17432 22816
35th 1200 21616 22816
53th 13696 9120 22816
Last 13688 9128 22816

根据以上table可以得出以下结论:

  1. 如果设置-Xms-Xmx一致,则Young GenOld Gen为固定值
  2. Young Genspace一直在变化,有时增加,有时减少。 old Gen相反。

在G1中,Young Gen的space在GC之后一直在变化,Parallel GC中的Young Gen的space总是固定的。 因此GCEasy无法用唯一的值来表示G1的每个gen的分配space,所以它选择取每个Gen 申请期间的最大值 运行。根据上面的table,space计算如下:

  • Young Gen的最大值为:13696(Mb) = 13.375(Gb) ≈ 13.38(Gb)
  • Old Gen的最大值为:21680(Mb) = 21.171(Gb)≈21.17(Gb)

两个值的近似值与下面的table完全吻合。

Generation Allocated Peak
Young Gen 13.38 3.37
Old Gen 21.17 485mb
Meta Space 1.5 n/a
Young + old + Meta 23.78 13.61