Skip to content

Commit

Permalink
ygc post
Browse files Browse the repository at this point in the history
  • Loading branch information
yoa1226 committed Oct 22, 2024
1 parent 2ea9628 commit af08cac
Show file tree
Hide file tree
Showing 2 changed files with 193 additions and 2 deletions.
189 changes: 187 additions & 2 deletions _posts/2024-09-05-g1-gc-young-gc-post.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,191 @@
---
layout: post
title: "G1 Young GC 之清理阶段"
title: "G1 Young GC 之收尾阶段"
date: 2024-09-05 11:00:00 +0200
tags: [GC, G1]
---
---

前文 GC 复制阶段已经将所有的对象从 cset 复制到其他 region,本文收尾阶段将对一些遗留问题进行处理。收尾阶段任务很多,仅讲解一些与前文相关性比较大的任务。

## 总览

` allocator()->release_gc_alloc_regions` 释放对象复制时使用的 region。

`post_evacuate_cleanup_1` 任务集合1。

`post_evacuate_cleanup_2` 任务集合2。

`_evac_failure_regions.post_collection` 重置记录失败信息的数据结构。

`rebuild_free_region_list` 重新构造空闲 region 列表。

`prepare_for_mutator_after_young_collection` 为 Java 线程活动准备 region,并将 Survivor 区域加入到回收集。

```cpp
void G1YoungCollector::post_evacuate_collection_set(G1EvacInfo* evacuation_info, G1ParScanThreadStateSet* per_thread_states) {

//omit process weak reference process

allocator()->release_gc_alloc_regions(evacuation_info);

post_evacuate_cleanup_1(per_thread_states);

post_evacuate_cleanup_2(per_thread_states, evacuation_info);

//concurrent gc
if (collector_state()->in_concurrent_start_gc()) {
enqueue_candidates_as_root_regions();
}

_evac_failure_regions.post_collection();


_g1h->rebuild_free_region_list();

_g1h->prepare_for_mutator_after_young_collection();

_g1h->expand_heap_after_young_collection();
}
```
## G1ClearCardTableTask
此任务是清空部分 region 的 card table。
`add_all_dirty_region` 在前面文章说过代表的是 cset 所有 region。由于 cset 中的对象都被清空,那么就不存在跨 region 指针,对应的 card table 区域也需要被清空。
`r->clear_cardtable()` 执行清空任务。
```cpp
new G1ClearCardTableTask(G1CollectedHeap::heap(), _all_dirty_regions, this);
void do_work(uint worker_id) override {
const uint num_regions_per_worker = num_cards_per_worker / (uint)G1HeapRegion::CardsPerRegion;
while (_cur_dirty_regions < _regions->size()) {
uint next = Atomic::fetch_then_add(&_cur_dirty_regions, num_regions_per_worker);
uint max = MIN2(next + num_regions_per_worker, _regions->size());
for (uint i = next; i < max; i++) {
G1HeapRegion* r = _g1h->region_at(_regions->at(i));
r->clear_cardtable();
}
}
}
```

## RestoreEvacFailureRegionsTask

此任务处理复制失败的 region,也就说 region 上还有对象没有被转移,需要做特殊处理。

`_chunk_bitmap` 用于记录被遍历的内存块。

`claim_chunk` 用于同步工作线程。

`zap_dead_objects` 填充活对象之间的区域。

```cpp
class G1PostEvacuateCollectionSetCleanupTask1::RestoreEvacFailureRegionsTask{

CHeapBitMap _chunk_bitmap;
void do_work(uint worker_id) override {
for (uint i = 0; i < total_chunks; i++) {
const uint chunk_idx = (start_chunk_idx + i) % total_chunks;
if (claim_chunk(chunk_idx)) {
process_chunk(worker_id, chunk_idx);
} } }
}

void process_chunk(uint worker_id, uint chunk_idx) {
//omit
HeapWord* first_marked_addr = bitmap->get_next_marked_addr(chunk_start, hr_top);
HeapWord* obj_addr = first_marked_addr;

do {
oop obj = cast_to_oop(obj_addr);
const size_t obj_size = obj->size();
HeapWord* const obj_end_addr = obj_addr + obj_size;

obj->init_mark();
hr->update_bot_for_block(obj_addr, obj_end_addr);

HeapWord* next_marked_obj_addr = bitmap->get_next_marked_addr(obj_end_addr, hr_top);
garbage_words += zap_dead_objects(hr, obj_end_addr, next_marked_obj_addr);
obj_addr = next_marked_obj_addr;
} while (obj_addr < chunk_end);

}
```
## RestorePreservedMarksTask
对于转移失败的对象,并且 markword 被存储的需要重新恢复。
```cpp
class G1PostEvacuateCollectionSetCleanupTask2::RestorePreservedMarksTask : public G1AbstractSubTask {
WorkerTask* _task;
public:
RestorePreservedMarksTask(PreservedMarksSet* preserved_marks) :
_task(preserved_marks->create_task()) { }
void do_work(uint worker_id) override { _task->work(worker_id); }
};
WorkerTask* PreservedMarksSet::create_task() {
return new RestorePreservedMarksTask(this);
}
//_preserved_marks_set->get(task_id)->restore_and_increment(&_total_size);
//restore()
void PreservedMarks::restore() {
while (!_stack.is_empty()) {
const PreservedMark elem = _stack.pop();
elem.set_mark(); //_o->set_mark(_m);
}
assert_empty();
}
```

## ProcessEvacuationFailedRegionsTask

在 Young GC 阶段清空 markbit。

## RedirtyLoggedCardsTask

处理 dirty card 任务对象,除了在 cset 中,并且没有对象存在的 reigon 都会被处理

```cpp
void do_card_ptr(CardValue* card_ptr) override {
G1HeapRegion* hr = region_for_card(card_ptr);
// Should only dirty cards in regions that won't be freed.
if (!will_become_free(hr)) {
*card_ptr = G1CardTable::dirty_card_val();
_num_dirtied++;
}
}

bool will_become_free(G1HeapRegion* hr) const {
// A region will be freed by during the FreeCollectionSet phase if the region is in the
// collection set and has not had an evacuation failure.
return _g1h->is_in_cset(hr) && !_evac_failure_regions->contains(hr->hrm_index());
}
```
## FreeCollectionSetTask
释放 cset,对于还有对象没有处理的 region ,如果存活对象小于某个阈值则需要加入到 cset 候选中,反之不处理。
对于清空的 reigon 则加入 `free_list` 中。
```cpp
virtual bool do_heap_region(G1HeapRegion* r) {
if (_evac_failure_regions->contains(r->hrm_index())) {
handle_failed_region(r);
} else {
handle_evacuated_region(r);
}
}
```

## 总结

本文简单的介绍了 G1 的收尾阶段,对其中感兴趣的内容读者可自行深入阅读源码。
6 changes: 6 additions & 0 deletions _posts/2024-09-10-g1-gc-young-gc-iter-obj.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
layout: post
title: "JVM 对象遍历"
date: 2024-09-05 11:00:00 +0200
tags: [GC, G1]
---

0 comments on commit af08cac

Please sign in to comment.