【问题标题】:Could increase gc time short lived object that has references to old lived object?可以增加引用旧对象的 gc 时间短寿命对象吗?
【发布时间】:2019-11-19 00:03:06
【问题描述】:

我需要澄清一下次要 gc 集合的行为方式。调用a() 或调用b() 在一个长期存在的应用程序中,如果它们在旧空间变大时表现得最差

//an example instance lives all application life cycle 24x7
public class Example {

    private Object longLived = new Object(); 

    public void a(){
        var shortLived = new ShortLivedObject(longLived); // longLived now is attribute
        shortLived.doSomething();
    }


    public void b(){
       new ShortLivedObject().doSomething(new Object()); // actually now is shortlived
    }

}

我的疑惑从何而来?我发现在使用的永久空间变大的应用程序中,次要 gc 暂停会增加。

做了一些测试,我发现如果我强制 jvm 使用选项a() 和另一个 jvm 使用选项 b(),那么当旧空间变大时,带有选项 b() 的 jvm 具有更短的暂停持续时间但我不知道为什么。

我在应用程序中解决了这个问题,在 4096 中使用此属性 XX:ParGCCardsPerStrideChunk,但我想知道我上面描述的情况是否会导致 gctimes 增加导致 gccard 表中的扫描速度较慢或者我不知道或根本不相关的东西。

【问题讨论】:

  • 一般来说,你不应该期望它们完全不同。
  • @LouisWasserman 当旧空间变大时会发生这种情况,但也许你是对的,这个例子与实际发生的事情无关,我正在寻找一些澄清。我注意到时间响应的百分位 99 和 p99.9 的差异
  • 这里的最大问题是您使用的是已弃用的 GC 收集器 - CMS。你需要切换到G1(或者更好的Shenandoah)看看那里会发生什么。第二个问题是,我怀疑您是否知道LongLivedObject 实际上 是一个 long 存活对象——它是否被 GC 根引用?第三,您经常混淆术语:CMSyoung 一代有一个 STW 停顿,在老一代有两个短暂停顿,还有很多其他你混淆的东西。
  • 您还提出了 4 个不同的问题,我可以在这里数一数,所有这些问题都非常笼统 - 因此您最好的机会是获得通用答案。
  • @Eugene 我知道这是一个长寿对象。我没有混淆,我总是专注于 ParNew 的小 gc。 .我不是在寻找标志,我只是想了解使用选项 b() 是否比使用 a() 更高效。也许我不清楚,我必须改进问题

标签: java java-8 garbage-collection jvm concurrent-mark-sweep


【解决方案1】:

免责声明:我目前还不是 GC 专家,但最近为了好玩而进入这些细节。

正如我在 cmets 中所说,您正在使用已弃用的收集器,没有人支持它,也没有人想使用它,切换到 G1 或者更好的恕我直言切换到 Shenandoah :从这个简单的开始第一件事。

我只能假设增加 ParGCCardsPerStrideChunk 的默认值,这可能得益于一些ms (尽管我们没有证据) .我们也没有来自 GC、CPU 活动、日志等的日志;因此,这很难回答。

如果你确实有一个大堆(几十 GB)并且一个大的年轻空间 并且你有足够的 GC 线程,将该参数设置为更大的值 可能确实有帮助,可能甚至与您提到的card table 有关。进一步阅读原因。

CMS 将堆分成old spaceyoung space,它可以选择任何其他鉴别器,但他们选择了age(就像G1)。为什么需要这个?能够仅扫描和收集堆的部分区域(完全扫描它非常昂贵)。 young space 是用stop-the-world 暂停收集的,所以最好小一点,否则你会不开心;这也是为什么您通常会看到更多 young collectionsold ones 相比。

扫描young space 时唯一的问题是:如果有来自old space 的引用指向来自young space 的对象,会发生什么?收集这些显然是错误的,但是扫描整个old space 以找出答案将完全违背generational collections 的目的。因此:card table

这会跟踪从old spaceyoung space 的引用,因此它知道究竟什么是垃圾。 G1 也使用了card table,但也添加了RememberedSet(此处不详述)。在实践中,RememberedSets 被证明是巨大的,这就是为什么G1 成为代际。 (仅供参考:Shenandoah 使用 matrix 而不是 card table - 使其代代相传)。

所以这个巨大的介绍是为了表明确实增加ParGCCardsPerStrideChunk 可能会有所帮助。您正在为每个 GC 线程提供更多工作空间。默认值为256,卡表为512 bytes,即

256 * 512 = 128KB per stride of old generation

例如,如果您有一堆32 GB,那是多少数十万步?恐怕太多了。

现在,您为什么还要在这里讨论reference counting?我不知道。


您展示的示例具有不同的语义,因此很难推理;不过我还是会努力的。你必须明白对象的可达性只是一个从一些开始的图(称为GC roots)。我们先来看这个例子:

public void b(){
   new ShortLivedObject().doSomething(new Object()); // actually now is shortlived
}

ShortLivedObject 实例在doSomething 方法调用完成并且其范围 仅在方法内时被“遗忘”,因此没有人可以访问它。因此剩下的部分是关于doSomething 的参数:new Object。如果doSomething 没有对它得到的参数做任何可疑的事情(使它可以通过GC root 图表访问),那么在doSomething 完成之后,它也将有资格进行GC。但即使doSomething 使new Object 可达,它仍然意味着ShortLivedObject 实例有资格进行GC。

因此,即使Example 可达(意味着它不能被收集),ShortLivedObjectnew Object() 可以 被收集。它可能看起来像这样:

                 new Object()
                      |
                     \ /
               ShortLivedObject           
                      |
                     \ /
GC Root -> ... - > Example

您可以看到,一旦 GC 将扫描 Example 实例,它可能不会扫描 ShortLivedObject(这就是为什么 garbage 被标识为与 live 对象相反)。因此 GC 算法将简单地丢弃整个图而不扫描它。


第二个例子不同:

public void a(){
    var shortLived = new ShortLivedObject(longLived);
    shortLived.doSomething();
}

不同之处在于 longLived 这里是一个 instance 字段,因此,图表看起来会有些不同:

                ShortLivedObject
                      |
                     \ /
                  longLived         
                     / \
                      |
GC Root -> ... - > Example

很明显,在这种情况下ShortLivedObject 可以被收集,但不能 longLived

你要明白,这根本不重要,如果Example实例可以被收集;这个图不会被遍历,Example 使用的所有东西都可以被收集。

您现在应该能够理解使用方法a 可以保留更多的垃圾并可能将其移动到old space(当它们变得足够老时)并且可以 可能会使您的young pauses 更长并且确实增加ParGCCardsPerStrideChunk 可能有点帮助;但这是高度推测性的,您需要一个非常糟糕的相同分配模式才能发生所有这一切。如果没有日志,我高度对此表示怀疑。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-10-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多