Skip to content

Commit

Permalink
obj iter
Browse files Browse the repository at this point in the history
  • Loading branch information
yoa1226 committed Oct 30, 2024
1 parent 3fc27e2 commit 70206ed
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 6 deletions.
115 changes: 115 additions & 0 deletions _posts/2024-09-10-g1-gc-ter-obj.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
---
layout: post
title: "JVM 对象遍历"
date: 2024-09-05 11:00:00 +0200
tags: [GC, G1]
---

GC 中,对于存活的对象需要遍历其全引用类型的属性,前面的文章并没有解释对象是如何被遍历的,本文参考 [以 ZGC 为例,谈一谈 JVM 是如何实现 Reference 语义的](https://mp.weixin.qq.com/s?__biz=Mzg2MzU3Mjc3Ng==&mid=2247489586&idx=1&sn=4306549c480f668458ab4df0d4b2ea47&chksm=ce77de75f9005763016605e0d268e1a4393a83bfe2a281c915bbf55de99d25cda529195c2843&scene=178&cur_album_id=2291913023118213124#rd) (后文中称其为引文) 中 "JVM 如何遍历对象的引用关系图" 小节简单介绍对象的遍历。 读者一定要先读引文,再读本文就很简单。

## OopMapBlock

OopMapBlock 是对象中引用类型属性的结构,加快对象的遍历。由于引用类型的字段不都是连续的,所以 OopMapBlock 对于某一个 class 会有多个。如图,图片来自引文。

<image src="/assets/ygc-obj-iter/omb.png" width="60%">

## 遍历逻辑

在回收阶段,方法 `G1ParScanThreadState::do_copy_to_survivor_space` 拷贝存活对象的时候需要遍历其引用的属性。

对于普通对象:

```cpp
obj->oop_iterate_backwards(&_scanner, klass);
```
数组类型的对象:
```cpp
to_array->oop_iterate_range(&_scanner, 0, checked_cast<int>(step._index));
```

对于 Java 对象,对象头中存储对象的类型。

```cpp
class oopDesc {
volatile markWord _mark;
union _metadata {
Klass* _klass;
narrowKlass _compressed_klass;
} _metadata
}
```
首先根据 `Klass` 类型拿到对应的函数,然后调用函数。
```cpp
//->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 类型,都有对应的遍历函数。

```cpp
static FunctionType function(Klass* klass) {
return _table._function[klass->kind()];
}


void set_init_function() {
_function[KlassType::Kind] = &init<KlassType>;
}
```
调用链是:
```cpp
// &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` 的信息遍历对象。

```cpp
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 语义的](https://mp.weixin.qq.com/s?__biz=Mzg2MzU3Mjc3Ng==&mid=2247489586&idx=1&sn=4306549c480f668458ab4df0d4b2ea47&chksm=ce77de75f9005763016605e0d268e1a4393a83bfe2a281c915bbf55de99d25cda529195c2843&scene=178&cur_album_id=2291913023118213124#rd) 简单的介绍了对象的遍历。
6 changes: 0 additions & 6 deletions _posts/2024-09-10-g1-gc-young-gc-iter-obj.md

This file was deleted.

Binary file added assets/ygc-obj-iter/omb.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 70206ed

Please sign in to comment.