【问题标题】:-XX:G1ReservePercent and to-space exhausted-XX:G1ReservePercent 和空间耗尽
【发布时间】:2020-10-07 11:58:15
【问题描述】:

我试图了解-XX:G1ReservePercent 的实际作用。我在official documentation找到的描述不是很全面:

设置保留内存的百分比以保持空闲以减少 空间溢出的风险。默认值为 10%。当你 增加或减少百分比,确保调整总数 相同数量的 Java 堆。

to-space耗尽日志条目的描述是这样的:

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

[...]

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

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

[...]

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

但这与以下official tuning advice in case of Full GC(强调我的)相矛盾:

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

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

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

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

【问题讨论】:

    标签: java jvm g1gc


    【解决方案1】:

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

    这个标志的最佳描述是here:

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

    非常好,所以这与“促销失败”(无论是什么)有关。但是根据你的粗体引用,这也与AdaptiveIHOP 有关吗?好吧yes, this parameter matters only in AdaptiveIHOP(默认开启)。

    另外需要注意的是G1ReservePercentageno guarantee to be maintained all the time,这是尽力而为。

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

    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周期,是minormixed或者majorG1knows how many regions are free

    _free_regions_at_end_of_collection = _g1h->num_free_regions();
    

    当然是"free list"的长度:

    return _free_list.length();
    

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

    它充当safety-net(代码中的 cmets 使这更容易理解)。这是需要的,希望它能避免Full GC。因为如果没有空闲区域(或足够多的区域)来移动活动对象,则需要进行 Full GC(很可能后面还有 young GC)。


    this message is present in logs 时,这个值通常被认为很小。要么增加它,要么更多更好地为应用程序提供更多堆。

    【讨论】:

      猜你喜欢
      • 2017-09-16
      • 2012-03-08
      • 1970-01-01
      • 2011-05-28
      • 1970-01-01
      • 1970-01-01
      • 2021-04-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多