在 G1 中将 G1HeapWastePercent 设置为零的后果
Posted
技术标签:
【中文标题】在 G1 中将 G1HeapWastePercent 设置为零的后果【英文标题】:Consequences of setting G1HeapWastePercent to zero in G1 【发布时间】:2022-01-23 08:02:58 【问题描述】:美好的一天,我在生产中使用 G1(Hotspot JDK 11)并试图了解它是如何工作的。据我了解,G1中的Old GC只清理那些充满垃圾的区域,否则区域会被放入一些队列中。
稍后会触发混合 GC,它将使用 amount of Old generations/G1MixedGCCountTarget
旧区域清理年轻区域。要扫描的旧区域由G1MixedGCLiveThresholdPercent
确定,默认情况下为 65%,即如果该区域的 65% 是垃圾,那么它将被清除。
但是我不确定我是否理解G1HeapWastePercent
的含义。
来自官方文档
设置您愿意浪费的堆百分比。当 >reclaimable 百分比小于堆浪费百分比时,Java >HotSpot VM 不会启动混合垃圾回收周期。默认值为 10%。此设置在 Java HotSpot VM 版本 23 中不可用。
假设区域包含 65% 的垃圾。 G1 开始将生命对象从年轻区域移动到一个充满垃圾的旧区域,一旦这个区域只包含 10% 的垃圾,然后 G1 切换到另一个旧区域区域。如果我的假设是正确的,那么将G1HeapWastePercent
设置为 0 将用生命物体完全填充这个区域。这是正确的吗 ?如果时间延迟不是我的应用程序的优先事项,我将 G1HeapWastePercent 设置为零有什么好处吗?
【问题讨论】:
【参考方案1】:首先,我想你可能误解了G1MixedGCLiveThresholdPercent
的效果(在Jdk7中默认值为65%,在Jdk 11中85%默认值)。
G1MixedGCLiveThresholdPercent
不是垃圾对象的空间比例,而是活对象的空间比例。如果某个区域的活体空间超过 85%(在 jdk11 中),则该区域将不会被选入
collection set
(区域集合待回收)
其次,G1HeapWastePercent
(Jdk7默认为10%,Jdk11默认为5%)
是触发 Mixed GC 和退出 Mixed GC 的条件。
当collection set
中的垃圾对象占总堆分配空间的5%以上(在jdk11中)时,
Mixed GC会被触发,而退出Mixed GC的充分条件之一就是
collection set
中的垃圾对象率低于5%。
因此,如果G1HeapWastePercent
设置为0%,只要收集集中有垃圾对象,就会触发Mixed GC。
那么退出混合GC的充分条件将变为collection set
为空,
因为每次 Mixed GC 都会从 collection set
中移除回收的区域。
最后想给大家解释一下G1 GC的执行过程,让大家更好的理解整个过程。
G1 包含 3 个阶段,concurrent marking
、Only Young GC
和 Mixed GC
。大致流程如下:
Only Young GC
结束,判断是否需要启动concurrent marking
concurrent marking
完成后,将计算每个区域(老年代)的活动对象和垃圾对象占用的空间。
-
然后生成
collection set
(要回收的old region collection),只有存活对象大小占region总大小超过G1MixedGCLiveThresholdPercent的old generation region才会进入collection set
。
之后对collection set
进行排序,_gc_efficiency
最高的排名第一。
collection set
中的reclaimable_percent
超过G1HeapWastePercent
%,则稍后会触发Mixed GC
。
Mixed GC
将选择所有年轻区域,old_region_length
的旧区域被回收。
-
Mixed GC执行结束时,如果
reclaimable_percent
仍然超过G1HeapWastePercent
%,那么稍后会再次执行Mixed GC
。
让我解释一下下面提到的几个参数和概念:
G1MixedGCLiveThresholdPercent
-
openjdk11中默认值为85,G1MixedGCLiveThresholdPercent
相关使用位置为mixed_gc_live_threshold_bytes,用于计算单个区域内物体的存活率阈值。超过此阈值的区域将不会进入
collection set
。
_gc_efficiency
-
单个区域的回收价值
_gc_efficiency =
the size of garbage objects in a single region
/ the time it takes to transfer this region
如果区域内的垃圾对象越多,传输时间越短,_gc_efficiency 就会越高。
G1HeapWastePercent
-
openjdk11中默认值为5,G1HeapWastePercent
相关代码next_gc_should_be_mixed用于判断下一次GC是否为
Mixed GC
。
reclaimable_percent
-
reclaimable_percent =
garbage object size
/ total space size
这里的垃圾对象是指collection set
中垃圾对象的总大小
G1MixedGCCountTarget
-
openjdk11中默认值为8,G1MixedGCCountTarget
表示一旦触发 Mixed GC,Expect 会执行 8 次 Mixed GC。
G1OldCSetRegionThresholdPercent
-
openjdk11中默认值为10,G1OldCSetRegionThresholdPercent
每次Mixed GC,选择的old_region_length都有一个最大值
最大值 =
the number of allocated regions in heap
* 10 / 100
old_region_length
-
这个值表示这个
Mixed GC
选择collecion set
中Old Regions的old_region_length
进行回收
这个值的下限是min_old_cset_length
,上限是max_old_cset_length
min_old_cset_length
= the size of collection set / G1MixedGCCountTarget
。
max_old_cset_length
= the number of allocated regions in heap * G1OldCSetRegionThresholdPercent / 100
因为G1会严格控制每一个GC Pause Time
,所以最终old_region_length受到gc暂停时间的约束。但是混合 GC 会尽可能多地将 collecion set
中的区域放入 old_region_length
,直到回收这些区域所需的总时间接近估计的 GC Pause Time
。
【讨论】:
这真的很有帮助,非常感谢,你甚至提供了 jdk 源代码的链接,非常棒,现在我知道实际发生了什么 我认为你对 G1MixedGCCountTarget 的描述不正确,数字 8 表示 MixedGc 的目标数量而不是选择多少个旧区域,旧区域的数量将由上限确定(G1OldCSetRegionThresholdPercent ) 或当可回收空间小于 G1HeapWastePercent 时。我说的对吗? 是的,你的意见是正确的。感谢您的提醒,我更正了答案中 G1MixedGCCountTarget 的解释。以上是关于在 G1 中将 G1HeapWastePercent 设置为零的后果的主要内容,如果未能解决你的问题,请参考以下文章