首页 > 解决方案 > -XX:G1ReservePercent 和空间耗尽

问题描述

我试图了解-XX:G1ReservePercent实际做了什么。我在官方文档中找到的描述并不是很全面:

设置保留内存的百分比以保持空闲,以降低 to-space 溢出的风险。默认值为 10%。当您增加或减少百分比时,请确保将总 Java 堆调整相同的数量。

并且对空间耗尽日志条目的描述是这样的:

当您在日志中看到空间溢出/耗尽消息时,G1 GC 没有足够的内存用于幸存者或提升对象,或两者兼而有之。

[...]

要缓解此问题,请尝试以下调整:

增加-XX:G1ReservePercent选项的值(以及相应的总堆)以增加“to-space”的保留内存量。

[...]

从引用来看,这to-space exhausted意味着在执行混合疏散时,我们没有足够的自由区域来转移幸存者。

但这与以下在 Full GC 情况下的官方调整建议相矛盾(强调我的):

强制 G1 提前开始标记。G1 根据早期的应用程序行为自动确定启动堆占用百分比 (IHOP) 阈值。如果应用程序行为发生变化,这些预测可能是错误的。有两个选项:通过修改 增加自适应 IHOP 计算中使用的缓冲区来降低何时开始空间回收的目标占用率 -XX:G1ReservePercent

那么缓冲区是什么,设置有什么作用-XX:G1ReservePercent(乍一看 AdaptiveIHOP 与它无关......)?

它是否总是保留一些堆空间,所以当混合疏散发生时,我们总是有空闲区域可以将幸存者移动到?

还是空间用于 G1 内部管家任务?如果是这样,则不清楚目标空间包含哪些数据以致耗尽?

标签: javajvmg1gc

解决方案


对我来说,理解它的真正作用,意味着去源代码。我选择了jdk-15

这个标志的最佳描述在这里

它决定了我们应该在堆中拥有的最小储备,以最小化提升失败的概率。

太好了,所以这与“促销失败”(无论是什么)有关。但是根据你的粗体字,这也有关系AdaptiveIHOP吗?是的,这个参数只在 AdaptiveIHOP 中重要(默认情况下是打开的)。

另外需要注意的是,不能保证一直维护G1ReservePercentage,这是尽力而为。

如果你看看它在下一行是如何使用的:

if (_free_regions_at_end_of_collection > _reserve_regions) {
    absolute_max_length = _free_regions_at_end_of_collection - _reserve_regions;
}

事情开始变得有意义(对于那个大胆的声明)。请注意如何提取_reserve_regions某些计算。将为“促销失败”保留该空间(我们将解决这个问题)。G1

如果G1保留该空间,则意味着可用于实际分配的空间更少。因此,如果您“增加此缓冲区”(G1ReservePercent正如报价所建议的那样变大),则新对象的空间会变,因此GC需要启动的时间会更快,因此需要进行空间回收的时间将也快来(“降低何时开始空间回收的目标占用率......”)。这是一个复杂的句子,但用简单的话来说,它意味着:

如果增加G1ReservePercentage,则需要更快地回收空间(更频繁的 GC 调用)。

公平地说,这是显而易见的。并不是说我同意您应该增加该值,但这就是那句话的意思。


在某个 GC 周期之后,be that或 ,知道minor多少个区域是空闲的mixedmajorG1

_free_regions_at_end_of_collection = _g1h->num_free_regions();

当然,哪个是“空闲列表”的长度:

return _free_list.length();

基于这个值和_reserve_regions( G1ReservePercent) 加上目标暂停时间(200 ms默认情况下),它可以计算下一个周期需要多少个区域。到下一个周期结束时,可能会出现没有空区域的情况(或者空的区域无法获取所有应该移动的活动对象)。应该在哪里Eden移动活动对象(Survivor),或者,如果old region是碎片化的 -应该将活动对象移动到哪里进行碎片整理?这就是这个缓冲区的用途。

它充当安全网(代码中的注释使这更容易理解)。这是需要的,希望它能避免Full GC. 因为如果没有空闲区域(或足够多的区域)来移动活动对象,则需要发生 Full GC(很可能后面跟着young GC也)。


当这条消息出现在日志中时,这个值通常被认为很小。要么增加它,要么更好地为应用程序提供更多堆。


推荐阅读