Remember Set的写屏障
写屏障是指,在改变特定内存的值(实际上也就是写入内存)的时候额外执行的一些动作。在大多数的垃圾回收算法中,都利用到了写屏障。写屏障通常用于在运行时探测并记录回收相关指针(interesting pointer),在回收器只回收堆中部分区域的时候,任何来自该区域外的指针都需要被写屏障捕获,这些指针将会在垃圾回收的时候作为标记开始的根。JAVA使用的其余的分代的垃圾回收器,都有写屏障。举例来说,每一次将一个老年代对象的引用修改为指向年轻代对象,都会被写屏障捕获,并且记录下来。因此在年轻代回收的时候,就可以避免扫描整个老年代来查找根。
G1垃圾回收器的写屏障和RS是相辅相成的,也就是记录Region内部的指针。这种记录发生在写操作之后。对于一个写屏障来说,过滤掉不必要的写操作是十分有必要的。这种过滤既能加快赋值器的速度,也能减轻回收器的负担。G1垃圾回收器采用的双重过滤
1.过滤掉同一个Region内部引用;2.过滤掉空引用;
G1的垃圾回收器的写屏障使用一种两级的log buffer结构:
1.global set of filled buffer:所有线程共享的一个全局的,存放填满了的log buffer的集合;2.thread log buffer:每个线程自己的log buffer。所有的线程都会把写屏障的记录先放进去自己的log buffer中,装满了之后,就会把log buffer放到 global set of filled buffer中,而后再申请一个log buffer;
写屏障 (Write Barrier) 也是GC里的一个关键技术(不是linux里的membarrier),当发生引用关系的更新时,通过写屏障来(这里指转移用的写入屏障)记录这个引用关系的变更,只是一系列函数而已,就像这样(伪代码):
代码语言:javascript复制def evacuation_write_barrier(obj, field, newobj){
//检查引用和被引用新对象是否在同一个区域
if(!check_cross_ref(obj, newobj)){
return
}
//不重复添加dirty_card
if(is_dirty_card(obj)){
return
}
to_dirty(obj);
//将obj添加到newobj所在region的rs
add_to_rs(obj, newobj);
}
为了便于理解,上面的伪代码屏蔽了一些细节,了解核心工作内容即可