Shenandoah 2.0 消除转发指针

Eug*_*ene 3 java garbage-collection jvm shenandoah

Shenandoah 1.0每个对象中都有一个额外的头文件——称为forwarding pointer. 为什么需要它,导致它被消除的原因是什么Shenandoah 2.0

Eug*_*ene 6

首先,每个 java 对象都有两个头文件:klassmark. 它们一直存在于每个实例中(例如,它们可以稍微改变 JVM在内部使用最近的 JVM 处理其标志的方式)并且出于各种原因使用(将在答案中仅详细介绍其中一个) )。

这个答案的第二部分forwarding pointer字面上需要 a 。将需要在这两个和的(虽然可以跳过某些字段类型的障碍-不细讲)。用非常简单的话来说,它极大地简化了并发复制。正如那个答案中所说,它允许自动切换到对象的新副本,然后同时更新所有引用以指向该新对象。forwarding pointerread barrierwrite barrierShenandoah 1.0forwarding pointer

事情已经改变了一个位Shenandoah 2.0,其中“以空间不变的”到位:这意味着所有的写入和读取完成后通过to-space。这意味着一个有趣的事:曾经的to-space副本成立,from-copy从未使用过。想象一下这样的情况:

    refA            refB
      |               |
fwdPointer1 ---- fwdPointer2        
                      |
  ---------       ---------  
  | i = 0 |       | i = 0 | 
  | j = 0 |       | j = 0 | 
  ---------       ---------
Run Code Online (Sandbox Code Playgroud)

Shenandoah 1.0某些情况下,通过读取refA可以绕过屏障(根本不使用它)并且仍然通过from-copy. final例如,这对于字段是允许的(通过特殊标志)。这意味着即使to-space副本已经存在并且已经有对它的引用,仍然可能有读取(通过refA)会转到from-space副本。在Shenandoah 2.0这被禁止。

这些信息以一种相当有趣的方式被使用。Java 中的每个对象都对齐到 64 位 - 这意味着最后 3 位始终为零。所以,他们放弃了forwarding pointer并说:如果mark单词的最后两位是11(这是允许的,因为没有其他人以这种方式使用它)-> 这是 a forwarding pointer,否则to-space副本确实存在并且这是一个普通的标题。您可以在此处看到它的运行情况,并且可以在此处此处跟踪屏蔽。

它曾经是这样的:

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

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

| -------------------|
|        class       |
| -------------------|
Run Code Online (Sandbox Code Playgroud)

并转变为:

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

| -------------------|
|        class       |
| -------------------|
Run Code Online (Sandbox Code Playgroud)

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

  refA, refB            
       |               
      mark   (last two bits are 00)   
       |              
    ---------   
    | i = 0 |      
    | j = 0 |      
    ---------  
Run Code Online (Sandbox Code Playgroud)

GC开始。引用的对象refA/refB是活着的,因此必须被疏散(据说它在“集合集”中)。首先创建一个副本并原子地mark引用该副本(最后两位也被标记为11现在使其成为 aforwardee而不是 a mark word):

  refA, refB            
       |               
     mark (11) ------  mark (00)   
                           |
    ---------          ---------
    | i = 0 |          | i = 0 |
    | j = 0 |          | j = 0 |
    ---------          ---------
Run Code Online (Sandbox Code Playgroud)

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

       refA              refB            
         |                 |               
     mark (11) ------  mark (00)   
                           |
    ---------          ---------
    | i = 0 |          | i = 0 |
    | j = 0 |          | j = 0 |
    ---------          ---------
Run Code Online (Sandbox Code Playgroud)

refB可以同时移动,所以那么refA,最终没有对from-space对象的引用,它是垃圾。如果需要,这就是mark word作为 的方式forwarding pointer