3.4.5写屏障
内容来自 3.4.5写屏障中,描述伪共享问题的片段:
为了避免伪共享问题,一种简单的解决方案是不采用无条件的写屏障,而是先检查卡表标记,只有当该卡表元素未被标记过时才将其标记为变脏,即将卡表更新的逻辑变为以下代码所示:
if (CARD_TABLE[this address >> 9] != 0) { CARD_TABLE[this address >> 9]=0 }
这个地方文字描述和代码的意思不一致。文字描述未被标记过,逻辑判断应该是 CARD_TABLE[this address >> 9] == 0,而标记为变脏应该是 CARD_TABLE[this address >> 9]=1
这只是一个理解习惯上的问题,无论是“1代表变脏、0代表未变脏”,抑或是“0代表变脏,1代表为未变脏”都是可行的。
事实上HotSpot中是采用0代表变脏这种方式,所以书中跟随这个习惯。
; rsi is 'this' address
; rdx is setter param, reference to bar
; JDK7:
0x00007fc4a1071d5c: mov r10,rsi ; r10 = this
0x00007fc4a1071d5f: shr r10,0x9 ; r10 = r10 >> 9
0x00007fc4a1071d63: mov r11,0x7f7cb98f7000 ; r11 = CARD_TABLE
0x00007fc4a1071d6d: add r11,r10 ; r11 = CARD_TABLE + (this >> 9)
0x00007fc4a1071d70: movsx r8d,BYTE PTR [r11] ; r8d = CARD_TABLE[this >> 9]
0x00007fc4a1071d74: test r8d,r8d
0x00007fc4a1071d77: je 0x00007fc4a1071d7d ; if(CARD_TABLE[this >> 9] == 0) goto 0x00007fc4a1071d7d
0x00007fc4a1071d79: mov BYTE PTR [r11],0x0 ; CARD_TABLE[this >> 9] = 0
0x00007fc4a1071d7d: mov QWORD PTR [rsi+0x20],rdx ; this.foo = bar
ref:https://gist.github.com/nitsanw/71e5aaedeb5dce87e9c2#file-gistfile1-asm
你说的我理解了。不过采用 0 代表变脏这种方式,和3.4.4 记忆集与卡表,最后一段话(图3-5 卡表与卡页对应示意图 下面)描述有些不一致,容易让人迷惑。原话是: 一个卡页的内存中通常包含不止一个对象,只要卡页内有一个(或更多)对象的字段存在着跨代指针,那就将对应卡表的数组元素的值标识为1,称为这个元素变脏(Dirty),没有则标识为0。
感谢指正。前面讲解和图片中是以1为变脏的,这样确实容易让人迷惑,是应该修改示例代码统一起来。