1. 简介
并发标记是ZGC的第2个阶段,此阶段中,GC worker与Mutator并发工作,GC worker执行标记、load barrier和relocate。
并发线程从带标记对象列表开始,递归遍历对象及对象的成员变量并标记。
2. 源码分析
2.1 入栈
标记栈的size受ZMarkStackSpaceLimit参数控制,默认8G,合法值32MB到1TB之间。
share/gc/z/z_globals.hpp
product(size_t, ZMarkStackSpaceLimit, 8*G,
"Maximum number of bytes allocated for mark stacks")
range(32*M, 1024*G)
标记栈元素分为两种:
- 如果是普通对象,则直接入栈、递归标记即可。
- 如果是数组对象,全部入栈则可能引起溢出,需判断数组大小是否超过ZMarkPartialArrayMinSize(默认4KB),未超过则入栈标记,否则按ZMarkPartialArrayMinSize切分后入栈标记。
share/gc/z/zMarkStackEntry.hpp
ZMarkStackEntry(uintptr_t object_address, bool follow, bool finalizable) :
_entry(field_object_address::encode(object_address) |
field_follow::encode(follow) |
field_partial_array::encode(false) |
field_finalizable::encode(finalizable)) {
}
ZMarkStackEntry(size_t partial_array_offset, size_t partial_array_length, bool finalizable) :
_entry(field_partial_array_offset::encode(partial_array_offset) |
field_partial_array_length::encode(partial_array_length) |
field_partial_array::encode(true) |
field_finalizable::encode(finalizable)) {
}
share/gc/z/zMark.cpp
void ZMark::push_partial_array(uintptr_t addr, size_t size, bool finalizable) {
assert(is_aligned(addr, ZMarkPartialArrayMinSize), "Address misaligned");
ZMarkThreadLocalStacks* const stacks = ZThreadLocalData::stacks(Thread::current());
ZMarkStripe* const stripe = _stripes.stripe_for_addr(addr);
const uintptr_t offset = ZAddress::offset(addr) >> ZMarkPartialArrayMinSizeShift;
const uintptr_t length = size