-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
115 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) 简单的介绍了对象的遍历。 | ||
This file was deleted.
Oops, something went wrong.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.