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 语义的 简单的介绍了对象的遍历。