Shenandoah 2.0消除了转发指针 [英] Shenandoah 2.0 elimination of forwarding pointer

查看:183
本文介绍了Shenandoah 2.0消除了转发指针的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Shenandoah 1.0中,每个单个对象都有一个附加的标头-称为forwarding pointer.为什么需要它?导致在Shenandoah 2.0中将其消除的原因是什么?

In Shenandoah 1.0 every single Object had an additional header - called forwarding pointer. Why was that needed and what is the reason that lead to its elimination in Shenandoah 2.0?

推荐答案

首先,每个Java对象都有两个标头:klassmark.从一开始它们就一直存在于每个实例中(它们可以稍微改变JVM处理

First of all, every single java Object has two headers: klass and mark. They have been there in each instance since forever (they can slightly change how a JVM handles their flags internally with recent JVMs, for example) and are used for various reasons (will go into detail about only one of them a bit further in the answer).

forwarding pointer的需求实际上在答案的第二部分. forwarding pointerread barrier中的read barrierwrite barrier都需要 read 可能会跳过某些字段类型的障碍-不会详细介绍).用非常简单的话来说,它大大简化了并发复制.如该答案所述,它允许将forwarding pointer原子切换到该对象的新副本,然后同时更新所有引用以指向该新对象.

The need for a forwarding pointer is literally in the second part of this answer. The forwarding pointer is needed in both read barrier and write barrier in Shenandoah 1.0 (though the read could skip the barrier for some field types - will not go into detail). In very simple words it simplifies concurrent copy very much. As said in that answer, it allows to atomically switch the forwarding pointer to the new copy of the Object and then concurrently update all references to point to that new Object.

Shenandoah 2.0中,"to-space invariant"变为"to-space invariant".到位:意味着所有的写入和读取都通过to-space完成.这意味着一件有趣的事情:一旦建立了to-space副本,就不再使用from-copy.想象这样的情况:

Things have changed a bit in Shenandoah 2.0 where the "to-space invariant" is in place : meaning all the writes and reads are done via the to-space.This means one interesting thing : once the to-space copy is established, the from-copy is never used. Imagine a situation like this:

    refA            refB
      |               |
fwdPointer1 ---- fwdPointer2        
                      |
  ---------       ---------  
  | i = 0 |       | i = 0 | 
  | j = 0 |       | j = 0 | 
  ---------       ---------

Shenandoah 1.0中,有时通过refA读取 会绕过障碍(根本不使用它),并且通过from-copy读取 still .例如,这允许用于final字段(通过特殊标志).这意味着,即使to-space副本已经存在并且已经有对其的引用,仍可能会有 reads (通过refA)(将通过refA复制)到from-space副本.在Shenandoah 2.0中,这是禁止的.

In Shenandoah 1.0 there were cases when reading via the refA could bypass the barrier (not use it at all) and still read via the from-copy. This was allowed for final fields, for example (via a special flag). This means that even if to-space copy already existed and there were already references to it, there could still be reads (via refA) that would go to the from-space copy. In Shenandoah 2.0 this is prohibited.

此信息以相当有趣的方式使用. Java中的每个对象都按64位对齐-表示最后3位始终为 零.因此,他们放弃了forwarding pointer并说:如果mark字的最后两位是11(这是允许的,因为没有其他方式以这种方式使用它)->这是forwarding pointer,否则to-space副本不存在,并且这是普通标头.您可以看到它就在这里,您可以跟踪

This information was used in a rather interesting way. Every object in Java is aligned to 64 bits - meaning the last 3 bits are always zero. So, they dropped the forwarding pointer and said that : if the last two bits of the mark word are 11 (this is allowed since no else uses it in this manner) -> this is a forwarding pointer, otherwise the to-space copy does yet exists and this is a plain header. You can see it in action right here and you can trace the masking here and here.

它以前看起来像这样:

| -------------------|
| forwarding Pointer |
| -------------------|

| -------------------|
|        mark        |
| -------------------|

| -------------------|
|        class       |
| -------------------|

并已转换为:

| -------------------|
| mark or forwarding |     // depending on the last two bits
| -------------------|

| -------------------|
|        class       |
| -------------------|

所以这是一个可能的情况(为简单起见,我将跳过class header):

So here is a possible scenario (I'll skip class header for simplicity):

  refA, refB            
       |               
      mark   (last two bits are 00)   
       |              
    ---------   
    | i = 0 |      
    | j = 0 |      
    ---------  

GC启动.refA/refB引用的对象是活动的,因此必须撤离(据说它在收集集"中).首先创建一个副本,并自动使用mark引用该副本(最后两个位也标记为11,现在将其设置为forwardee而不是mark word):

GC kicks in. The object referenced by refA/refB is alive, thus must be evacuated (it is said to be in the "collection set"). First a copy is created and atomically mark is made to reference that copy (also the last two bits are marked as 11 to now make it a forwardee and not a mark word):

  refA, refB            
       |               
     mark (11) ------  mark (00)   
                           |
    ---------          ---------
    | i = 0 |          | i = 0 |
    | j = 0 |          | j = 0 |
    ---------          ---------

现在,其中一个mark word具有一个位模式(以11结尾),表明它是被转发者,而不再是标记词.

Now one of the mark words has a bit pattern (ends in 11) that indicates that it is a forwardee and not a mark word anymore.

       refA              refB            
         |                 |               
     mark (11) ------  mark (00)   
                           |
    ---------          ---------
    | i = 0 |          | i = 0 |
    | j = 0 |          | j = 0 |
    ---------          ---------

refB可以同时移动,因此refA最终不会引用from-space对象,这是垃圾.如果需要,这就是mark word充当forwarding pointer的方式.

refB can move concurrently, so then refA, ultimately there are not references to the from-space object and it is garbage. This is how mark word acts as a forwarding pointer, if needed.

这篇关于Shenandoah 2.0消除了转发指针的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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