Skip to content

Commit

Permalink
fix conc mark scan region and conc mark mark from root1
Browse files Browse the repository at this point in the history
  • Loading branch information
yoa1226 committed Oct 24, 2024
1 parent 6b6b619 commit 4700ada
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 1 deletion.
23 changes: 22 additions & 1 deletion _posts/2024-09-15-g1-conc-mark-root-region-scan.md
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,28 @@ void G1ConcurrentMark::scan_root_region(const MemRegion* region, uint worker_id)
}
```

注意上面的代码并没有对 `obj->oop_iterate_size(&cl)``obj` 对象本身进行标记,这是由于 root region 作为 gc root object 一定是存活的对象,此类对象不需要被标记。
注意上面的代码并没有对 `obj->oop_iterate_size(&cl)``obj` 对象本身进行标记,如果对 obj 进行标记会带来一定复杂性。

1. obj 可能是 survivor 区对象,也可能是 cset 候选区对象,由于在 root region scan 结束之后,可能进行 young gc,那么这些对象可能会被回收。那么在后续并发标记时会造成对象缺失。这也是 young GC 为什么要等待 root region scan 完成的原因。

2. survivor 区回收是在 young GC,不需要被标记就能被回收,cset 候选区已经被标记过了,无需重复标记。

```cpp
inline bool G1CMBitMap::iterate(G1CMBitMapClosure* cl, MemRegion mr) {
BitMap::idx_t const end_offset = addr_to_offset(mr.end());
BitMap::idx_t offset = _bm.find_first_set_bit(addr_to_offset(mr.start()), end_offset);

while (offset < end_offset) {
HeapWord* const addr = offset_to_addr(offset);
size_t const obj_size = cast_to_oop(addr)->size(); // 此时会造成对象缺失
offset = _bm.find_first_set_bit(offset + (obj_size >> _shifter), end_offset);
}
return true;
}
```
下面的图中可以看到,Young GC 和并发标记交替进行。
<image src="/assets/conc-root-region-scan/conc-root-region-sacn-ygc.png" width="80%">
`G1RootRegionScanClosure::do_oop_work` 方法标记对象,此对象为上述对象引用类型的属性。
Expand Down
85 changes: 85 additions & 0 deletions _posts/2024-09-20-g1-conc-mark-mark.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
---
layout: post
title: "G1 并发标记"
date: 2024-09-15 11:00:00 +0200
tags: [GC, G1]
---

前文介绍了并发标记的 root region scan 阶段,此阶段和 Young GC 中的 gc root scan 共同标记与 GC root 直接关联的对象,这些对象在 mark bitmap 对应的位置标记为存活。接下来并发标记阶段就是以这些对象为起点,开始标记与它们关联的对象,在此之前首先介绍此过程使用中到的数据结构。

## G1CMTask

`G1CMTask` 是工作线程的任务封装,并发标记执行的具体逻辑。

`_finger` 是当前工作线程遍历 region 的位置,它范围是 bottom <= _finger < tams。

当前工作的线程会将遍历到的对象加入 `_task_queue` 等待处理。

```cpp
class G1CMTask {
// Local finger of this task, null if we're not scanning a region
HeapWord* _finger;

// the task queue of this task
G1CMTaskQueue* _task_queue;
}
```
## G1ConcurrentMark
`G1ConcurrentMark` 是并发标记整个流程的封装。
`_finger` 是全局的 `_finger` ,表示所有线程中遍历最靠前的位置,范围是 `heap.start() <= _finger < heap.end()`
当线程本地队列 `_task_queue` 耗尽时会将任务加入到 `_global_mark_stack`。
```cpp
class G1ConcurrentMark {
// For grey objects
G1CMMarkStack _global_mark_stack; // Grey objects behind global finger
HeapWord* volatile _finger; // The global finger, region aligned,
// always pointing to the end of the
// last claimed regio
}
```

## 三色标记算法

在标记阶段 G1 采用三色标记算法,从 GC root 开始遍历对象,如图开始时只有与 gc root 直接关联的对象是黑色的,随着并发标记的进行,所有与 GC root 直接关联或者间接关联的对象都会变成黑色。

<image src="/assets/conc-mark/conc-mark-tri-color.png" width="80%"/>

注意这里说的对象染色并不是标记对象的某个属性为黑色或者灰色,以 G1 为例:

- 并发标记前:在 Young GC 阶段,将与之 gc root 关联的对象标记在 mark_bitmap 中,同理在 root region scan 阶段也会标记与之直接关联的对象。当对象已经在 mark_bitmap 标记,称对象被标记为黑色。此时除此之外的对象全部为白色对象,就是还没有遍历到的对象。

- 并发标记中:G1 从 heap 开始的位置起开始遍历,当遍历到的对象已经被标记,就会将它的属性引用加入到 `_task_queue` 中,称在队列中的对象标记为灰色。当处理任务队列时,对象会被拿出来在 mark_bitmap 上标记,此时对象被标记黑色,并且遍历对象引用属性加入到队列中。

- 并发标记后活者的对象都已经在 `mark_bitmap` 标记,为黑色对象,死对象未被标记,为白色对象。

由此可知,只有在标记过程中有灰色对象,标记之前和以后都只有黑色和白色对象,即标记之前和之后任务队列都为空。


## 并发标记

### todo

```cpp
//-> subphase_mark_from_roots
//->G1ConcurrentMark::mark_from_roots
class G1CMConcurrentMarkingTask : public WorkerTask {
G1ConcurrentMark* _cm;

public:
void work(uint worker_id) {
{
G1CMTask* task = _cm->task(worker_id);
if (!_cm->has_aborted()) {
do {
task->do_marking_step(G1ConcMarkStepDurationMillis, true , false);
} while (!_cm->has_aborted() && task->has_aborted());
} } }
}
```
Binary file added assets/conc-mark/conc-mark-tri-color.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
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 4700ada

Please sign in to comment.