雪兰多亚垃圾收集器负载参考障碍 [英] Shenandoah Garbage Collector Load Reference Barriers

查看:138
本文介绍了雪兰多亚垃圾收集器负载参考障碍的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于那些观察Shenandoah发展的人来说,并不是什么大秘密,主要的批评是它使用GC barriers进行每笔读写:是引用还是原始的

It is not a big secret for people who have watched the development of Shenandoah that a major criticism is that it employs GC barriers for every single write and read : be it reference or primitive.

Shenandoah 2.0声称这不再是问题,可以通过所谓的负载参考屏障来解决.究竟是怎么回事?

Shenandoah 2.0 claims that this is not a problem anymore and it is solved via so-called load reference barriers. How is this exactly happening?

推荐答案

我将假定读者知道什么是障碍以及为什么需要障碍.对于非常简短的介绍这是我的另一个答案主题.

I will assume that the reader knows what a barriers is and why it is needed. For a very short intro here is another answer of mine on the topic.

为了正确地理解这一点,我们需要首先查看最初的问题所在.我们来看一个简单的例子:

In order to properly understand that, we need to first look at where the initial problem really was. Let's take a rather simple example:

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

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

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

And now let's image a theoretical method like this:

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
     }
}

这个想法不是要显示一个正确的示例,而是要显示一个示例:

The idea is not to show a correct example, but an example that does:

  • 一个 read (user.zip;)

(user.age = ...)

现在,由于Shenandoah 1.0需要在所有地方引入障碍 ,因此该代码应如下所示:

Now because Shenandoah 1.0 needed to introduce barriers everywhere, this code would look:

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).user(RB代表read barrier)和WB(user).age(WB代表write barrier).现在,假设循环为hot-您将为这么多的障碍付出代价.即使在循环执行过程中没有GC活动,障碍也仍然存在,并且必须有代码有条件地检查是否需要执行障碍是否.

Notice the RB(holder).user (RB stands for read barrier) and WB(user).age (WB stands for write barrier). Now imagine that the loop is hot - you will pay the price for so many barriers. Even if there is no GC activity during the execution of the loop, the barriers are still in place and there has to be code that conditionally checks if the barrier needs to be executed or not.

长话短说:这些障碍绝不是免费的.

Long story short: those barriers are not free, by any means.

这些障碍是维持堆一致性所必需的,因为在撤离阶段中,内存中有对象的两个副本,因此您需要始终保持一致的读取和写入. "一致地"在这里表示Shenandoah 1.0中的 read 可能是从"to-space"开始发生的.或来自太空" (称为弱空间不变"),而 write 可能发生在to-space .

These barriers are needed to maintain heap consistency, because there are two copies of an Object in memory during evacuation phase, you need to always read and write consistently. Consistently here means that in Shenandoah 1.0 a read could have happened from the "to-space" or "from-space" (called "weak to-space invariant"), while a write could happen from to-space only.

Shenandoah 2.0表示将确保所谓的空间不变". (与之前的相对).基本上,它说所有写和读都将发生在到空间"中/进入到空间"中.在疏散期间,有两个副本的对象:一个在旧区域(称为从空间"),一个在新区域(称为到空间").

Shenandoah 2.0 says that it will ensure a so-called "to-space invariant" (as opposed to the previous weak one). Basically - it says that all the writes and reads are going to happen from/into the "to-space". During evacuation there are two copies of the Object: one in the old region (called "from-space") and one in the new region (called "to-space").

它实现了这种间隔".不变,但想法很简单,却很聪明.代替使用发生writes的障碍,它可以确保确定最初加载的对象是从"to-space"加载的.这是通过 load-reference-barriers 完成的.通过重构前面的示例,这很容易理解:

It achieves this "to-space" invariant with a rather simple, yet brilliant idea. Instead of employing barriers where writes happen, it ensures that the Object that was initially loaded was for sure loaded from the "to-space". This is done via load-reference-barriers. This is far more trivial to understand via refactoring the previous example:

  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障碍,并删除了另外两个障碍.因此,加载参考障碍发生在加载对象时,它们在定义站点称为 ,而不是在读取或存储对象时在其使用站点调用此 .您可以考虑一下,就好像在使用aloadgetField(供参考)的地方插入了这些障碍一样.

We have introduced the LRB barrier and removed two other. So, load-reference-barriers happen when an object is loaded, they call this : at the definition site, instead of when reading or storing to it, they call this at their use-site. You can think about it as if these barriers are inserted where aload and getField (for references) is used.

这篇关于雪兰多亚垃圾收集器负载参考障碍的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆