Shenandoah 垃圾收集器负载参考障碍

Shenandoah Garbage Collector Load Reference Barriers

对于看过 Shenandoah 发展的人来说这不是什么大秘密,一个主要的批评是它为 每个 使用 GC barriers写入和读取:无论是参考还是原始。

Shenandoah 2.0 声称这不再是问题,它已通过所谓的 加载参考屏障 解决。这到底是怎么回事?

我假设 reader 知道障碍是什么以及为什么需要障碍。非常简短的介绍 here is another answer of mine on the topic.

为了正确理解这一点,我们需要先看看最初的问题到底出在哪里。让我们举一个相当简单的例子:

static class User {
     private int zip;
     private int age;
}

static class Holder {
    
     private User user;
     // other fields we don't care about
      
}

现在让我们想象一下这样的理论方法:

public void access(Holder holder){
     User user = holder.user;
     for(;;){ // some loop here
         int zip = user.zip;
         System.out.println(zip);

         user.age = // some value taken from the loop for example
     }
}

我们的想法不是展示一个正确的例子,而是一个正确的例子:

  • a 阅读 (user.zip;)

  • a 写入 (user.age = ...)

现在因为 Shenandoah 1.0 需要在所有地方 引入障碍 ,这段代码看起来是:

public void access(Holder holder){
  User user = RB(holder).user;  
  for(;;){ // some loop here
      int zip = RB(user).zip;
      System.out.println(zip);

      WB(user).age = // some value taken from the loop for example
  }
}   

注意 RB(holder).userRB 代表 read barrier)和 WB(user).ageWB 代表 write barrier)。现在假设循环是 hot - 您将为这么多障碍付出代价。即使在循环执行期间没有 GC activity,屏障 仍然 并且必须有代码 有条件地 检查屏障是否需要执行。

长话短说:无论如何,这些障碍都不是免费的。

需要这些屏障来保持堆一致性,因为在疏散阶段内存中有两个个对象副本,你需要始终如一地阅读和写作。 Consistently 这里意味着在 Shenandoah 1.0read 可能发生在“to-space”或“from-space”(称为“弱 to-space 不变”),而 write 可能发生在 to-space only.


Shenandoah 2.0 表示它将确保 so-called “to-space 不变”(与之前的 weak 相对)。基本上-它说所有的写入和读取都将发生from/into“to-space”。在疏散期间有两个对象副本:一个在旧区域(称为“from-space”)和一个在新区域(称为“to-space”)。

它通过一个相当简单但绝妙的想法实现了这个“to-space”不变量。它不是在 writes 发生的地方使用障碍,而是确保最初加载的对象肯定是从“to-space”加载的。这是通过 load-reference-barriers 完成的。通过重构前面的示例,理解起来要简单得多:

  public void access(Holder holder){
      User user = LRB(holder).user;  
      for(;;){ // some loop here
          int zip = user.zip;
          System.out.println(zip);

          user.age = // some value taken from the loop for example
      }
  }

我们引入了 LRB 屏障并移除了另外两个屏障。因此,load-reference-barriers 发生在加载对象时,他们称之为: 在定义站点 ,而不是在读取或存储到它时,他们称之为 在他们 use-site。您可以将其视为在使用 aloadgetField(供参考)的地方插入这些障碍。