深入理解Java虚拟机——写屏障

1,551 阅读1分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

写屏障

卡表在产生跨代引用时变脏,Java虚拟机通过写屏障的方式来实现这个变脏的过程,即:在虚拟机层面通过AOP对“引用类型字段赋值”操作插入代码,在操作前的代码叫做“写前屏障”,操作后的代码叫做“写后屏障”,维护卡表使用的是“写后屏障”。

void oop_field_store(oop* field, oop new_value) {
    // 引用字段赋值
    *field = new_value;
    // 写后屏障完成卡表状态更新
    post_write_barrier(field, new_value);
}

写后屏障维护卡表是有额外开销的,但相比于在Minor GC阶段就扫描整个老年代而言这个代价相对较低。

伪共享问题

由于处理器的缓存系统是缓存行为单位存储,当多线程修改相互独立变量而这些变量有在同一个缓存行,就会影响性能。例如缓存行为64Byte,一个卡表元素占用一个Byte,那么64个卡表元素共享一个缓存行,这64个卡表元素对应了一块32KB的内存,如果不同线程同时对其更新就会出现伪共享问题,解决方法为先检查卡表的标记,只有该值没有被标记过才进行处理。

if (CARD_TABLE[this >> address] >> 9 != 1) {
    CARD_TABLE[this >> address] >> 9 = 1;
}

在JDK7后可以自行决定是否要开启卡表更新的条件判断,参数为

-XX: +UseCondCardMark

开启会增加一次额外判断的开销,但可以避免伪共享问题。