JVM 对象遍历
GC 中,对于存活的对象需要遍历其全引用类型的属性,前面的文章并没有解释对象是如何被遍历的,本文参考 以 ZGC 为例,谈一谈 JVM 是如何实现 Reference 语义的 (后文中称其为引文) 中 “JVM 如何遍历对象的引用关系图” 小节简单介绍对象的遍历。 读者一定要先读引文,再读本文就很简单。
OopMapBlock
OopMapBlock 是对象中引用类型属性的结构,加快对象的遍历。由于引用类型的字段不都是连续的,所以 OopMapBlock 对于某一个 class 会有多个。如图,图片来自引文。
遍历逻辑
在回收阶段,方法 G1ParScanThreadState::do_copy_to_survivor_space
拷贝存活对象的时候需要遍历其引用的属性。
对于普通对象:
obj->oop_iterate_backwards(&_scanner, klass);
数组类型的对象:
to_array->oop_iterate_range(&_scanner, 0, checked_cast<int>(step._index));
对于 Java 对象,对象头中存储对象的类型。
class oopDesc {
volatile markWord _mark;
union _metadata {
Klass* _klass;
narrowKlass _compressed_klass;
} _metadata
}
首先根据 Klass
类型拿到对应的函数,然后调用函数。
//->oopDesc::oop_iterate_backwards
//->OopIteratorClosureDispatch::oop_oop_iterate_backwards
void OopIteratorClosureDispatch::oop_oop_iterate_backwards(OopClosureType* cl, oop obj, Klass* klass) {
OopOopIterateBackwardsDispatch<OopClosureType>::function(klass)(cl, obj, klass);
}
_function
对于每个 class 类型,都有对应的遍历函数。
static FunctionType function(Klass* klass) {
return _table._function[klass->kind()];
}
void set_init_function() {
_function[KlassType::Kind] = &init<KlassType>;
}
调用链是:
// &init<KlassType> ->
// _table.set_resolve_function_and_execute
//set_resolve_function 绑定函数
//_function[KlassType::Kind](cl, obj, k); // 函数调用
//oop_oop_iterate_backwards
static void oop_oop_iterate_backwards(OopClosureType* cl, oop obj, Klass* k) {
((KlassType*)k)->KlassType::template oop_oop_iterate_reverse<T>(obj, cl);
}
oop_oop_iterate_reverse
根据 KlassType
的类型遍历对象。
以 InstanceKlass
为例,获取 nonstatic_oop_maps
的地址,根据 OopMapBlock
的信息遍历对象。
void InstanceKlass::oop_oop_iterate_reverse(oop obj, OopClosureType* closure) {
oop_oop_iterate_oop_maps_reverse<T>(obj, closure);
}
ALWAYSINLINE void InstanceKlass::oop_oop_iterate_oop_maps_reverse(oop obj, OopClosureType* closure) {
OopMapBlock* const start_map = start_of_nonstatic_oop_maps();
OopMapBlock* map = start_map + nonstatic_oop_map_count();
while (start_map < map) {
--map;
oop_oop_iterate_oop_map_reverse<T>(map, obj, closure);
}
}
void InstanceKlass::oop_oop_iterate_oop_map_reverse(OopMapBlock* map, oop obj, OopClosureType* closure) {
T* const start = obj->field_addr<T>(map->offset());
T* p = start + map->count();
while (start < p) {
--p;
Devirtualizer::do_oop(closure, p);
}
}
总结
本文参考 以 ZGC 为例,谈一谈 JVM 是如何实现 Reference 语义的 简单的介绍了对象的遍历。