在Shenandoah 1.0
每个单独的 Object 中都有一个额外的标题 - 称为forwarding pointer
. 为什么需要这样做,导致它被淘汰的原因是什么Shenandoah 2.0
?
1 回答
首先,每个 java 对象都有两个头文件:klass
和mark
. 它们一直存在于每个实例中(例如,它们可以稍微改变 JVM在内部使用最近的 JVM 处理其标志的方式)并且用于各种原因(将在答案中进一步详细介绍其中一个)。
对 a 的需要forwarding pointer
实际上是在这个答案的第二部分。两者和inforwarding pointer
都需要(尽管读取可以跳过某些字段类型的障碍 - 不会详细说明)。用非常简单的话来说,它非常简化了并发复制。正如该答案中所说,它允许原子地切换到对象的新副本,然后同时更新所有引用以指向该新对象。read barrier
write barrier
Shenandoah 1.0
forwarding pointer
在“to-space 不变量”的位置发生了一些变化Shenandoah 2.0
:这意味着所有的写入和读取都是通过to-space
. 这意味着一件有趣的事情:一旦to-space
建立了副本,from-copy
就永远不会使用 。想象一下这样的情况:
refA refB
| |
fwdPointer1 ---- fwdPointer2
|
--------- ---------
| i = 0 | | i = 0 |
| j = 0 | | j = 0 |
--------- ---------
在Shenandoah 1.0
某些情况下,通过读取refA
可以绕过障碍(根本不使用它)并仍然通过from-copy
. final
例如,字段允许这样做(通过特殊标志)。这意味着即使to-space
副本已经存在并且已经存在对它的引用,仍然可以读取(通过refA
)将转到from-space
副本。在Shenandoah 2.0
此是禁止的。
这些信息以一种相当有趣的方式使用。Java 中的每个对象都与 64 位对齐——这意味着最后 3 位始终为零。所以,他们放弃了并说:如果单词forwarding pointer
的最后两位是(这是允许的,因为没有其他人以这种方式使用它)-> 这是 a ,否则副本确实存在并且这是一个普通的标题。您可以在此处看到它的运行情况,您可以在此处和此处跟踪掩蔽。mark
11
forwarding pointer
to-space
它曾经看起来像这样:
| -------------------|
| forwarding Pointer |
| -------------------|
| -------------------|
| mark |
| -------------------|
| -------------------|
| class |
| -------------------|
并转变为:
| -------------------|
| mark or forwarding | // depending on the last two bits
| -------------------|
| -------------------|
| class |
| -------------------|
所以这是一个可能的场景(为简单起见,我将跳过class header
):
refA, refB
|
mark (last two bits are 00)
|
---------
| i = 0 |
| j = 0 |
---------
GC
开始。 引用的对象refA/refB
是活动的,因此必须撤离(据说它在“集合集”中)。首先创建一个副本并以原子mark
方式引用该副本(最后两位也被标记为11
现在使其成为 aforwardee
而不是 a mark word
):
refA, refB
|
mark (11) ------ mark (00)
|
--------- ---------
| i = 0 | | i = 0 |
| j = 0 | | j = 0 |
--------- ---------
现在其中一个mark word
s 有一个位模式(以 结尾11
),表明它是转发者而不是标记词。
refA refB
| |
mark (11) ------ mark (00)
|
--------- ---------
| i = 0 | | i = 0 |
| j = 0 | | j = 0 |
--------- ---------
refB
可以同时移动,所以refA
最终没有对from-space
对象的引用,它是垃圾。如果需要,这就是mark word
充当 的方式。forwarding pointer