Mark Compact Sweep
V8的内存回收机制之Mark-Compact的Sweep功能
其定义位于//v8/src/heap/mark-compact.cc
的MarkCompactCollector::Sweep
函数:
完成工作:
- 按照特定顺序清理v8堆中的各个内存空间(大对象,普通页,新生代对象)
- 检查是否为MemoryChunk::BLACK_ALLOCATED标志位,代表为存活对象,不是则进行下一步检查
- 检查是否标记过,是则代表存活,否则代表对象已死亡,需要释放;普通页以及新生代内存释放操作在evacuate阶段进行。存在三种sweep函数
showLineNumbers 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69void MarkCompactCollector::Sweep() {
DCHECK(!sweeper_->sweeping_in_progress());
DCHECK(queued_pages_to_be_freed_.empty());
sweeper_->InitializeMajorSweeping();
TRACE_GC_EPOCH_WITH_FLOW(
heap_->tracer(), GCTracer::Scope::MC_SWEEP, ThreadKind::kMain,
sweeper_->GetTraceIdForFlowEvent(GCTracer::Scope::MC_SWEEP),
TRACE_EVENT_FLAG_FLOW_OUT);
state_ = SWEEP_SPACES;
{
GCTracer::Scope sweep_scope(heap_->tracer(), GCTracer::Scope::MC_SWEEP_LO,
ThreadKind::kMain);
SweepLargeSpace(heap_->lo_space());
}
{
GCTracer::Scope sweep_scope(
heap_->tracer(), GCTracer::Scope::MC_SWEEP_CODE_LO, ThreadKind::kMain);
SweepLargeSpace(heap_->code_lo_space());
}
if (heap_->shared_space()) {
GCTracer::Scope sweep_scope(heap_->tracer(),
GCTracer::Scope::MC_SWEEP_SHARED_LO,
ThreadKind::kMain);
SweepLargeSpace(heap_->shared_lo_space());
}
{
GCTracer::Scope sweep_scope(heap_->tracer(), GCTracer::Scope::MC_SWEEP_OLD,
ThreadKind::kMain);
StartSweepSpace(heap_->old_space());
}
{
GCTracer::Scope sweep_scope(heap_->tracer(), GCTracer::Scope::MC_SWEEP_CODE,
ThreadKind::kMain);
StartSweepSpace(heap_->code_space());
}
if (heap_->shared_space()) {
GCTracer::Scope sweep_scope(
heap_->tracer(), GCTracer::Scope::MC_SWEEP_SHARED, ThreadKind::kMain);
StartSweepSpace(heap_->shared_space());
}
{
GCTracer::Scope sweep_scope(
heap_->tracer(), GCTracer::Scope::MC_SWEEP_TRUSTED, ThreadKind::kMain);
StartSweepSpace(heap_->trusted_space());
}
if (heap_->shared_trusted_space()) {
GCTracer::Scope sweep_scope(
heap_->tracer(), GCTracer::Scope::MC_SWEEP_SHARED, ThreadKind::kMain);
StartSweepSpace(heap_->shared_trusted_space());
}
{
GCTracer::Scope sweep_scope(heap_->tracer(),
GCTracer::Scope::MC_SWEEP_TRUSTED_LO,
ThreadKind::kMain);
SweepLargeSpace(heap_->trusted_lo_space());
}
if (v8_flags.minor_ms && heap_->new_space()) {
GCTracer::Scope sweep_scope(heap_->tracer(), GCTracer::Scope::MC_SWEEP_NEW,
ThreadKind::kMain);
StartSweepNewSpace();
}
sweeper_->StartMajorSweeping();
} - SweepLargeSpace:大对象空间
- StartSweepSpace:普通分页空间
- StartSweepNewSpace:新生代空间(如果开启minor-ms)
最终启动并发清理StartMajorSweeping
MarkCompactCollector::SweepLargeSpace,处理大对象空间:showLineNumbers 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41void MarkCompactCollector::SweepLargeSpace(LargeObjectSpace* space) {
PtrComprCageBase cage_base(heap_->isolate());
size_t surviving_object_size = 0;
const bool postpone_freeing = ShouldPostponeFreeingEmptyPages(space);
const bool add_to_pool =
v8_flags.large_page_pool && space->identity() == NEW_LO_SPACE;
DCHECK_IMPLIES(add_to_pool, !postpone_freeing);
std::vector<LargePageMetadata*> pages_to_pool;
if (add_to_pool) {
pages_to_pool.reserve(space->memory_chunk_list().size());
}
for (auto it = space->begin(); it != space->end();) {
LargePageMetadata* current = *(it++);
DCHECK(!current->Chunk()->IsFlagSet(MemoryChunk::BLACK_ALLOCATED));
Tagged<HeapObject> object = current->GetObject();
if (!marking_state_->IsMarked(object)) {
// Object is dead and page can be released.
space->RemovePage(current);
if (postpone_freeing) {
queued_pages_to_be_freed_.push_back(current);
} else if (add_to_pool) {
pages_to_pool.push_back(current);
} else {
heap_->memory_allocator()->Free(MemoryAllocator::FreeMode::kImmediately,
current);
}
continue;
}
if (!v8_flags.sticky_mark_bits) {
MarkBit::From(object).Clear();
current->SetLiveBytes(0);
}
current->marking_progress_tracker().ResetIfEnabled();
surviving_object_size += static_cast<size_t>(object->Size(cage_base));
}
space->set_objects_size(surviving_object_size);
if (add_to_pool && !pages_to_pool.empty()) {
heap()->memory_allocator()->FreeLargePagesPooled(std::move(pages_to_pool));
}
}
MarkCompactCollector::StartSweepSpace函数,处理普通页:
1 | void MarkCompactCollector::StartSweepSpace(PagedSpace* space) { |
MarkCompactCollector::SweepNewSpace函数,处理新生代对象:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 void MarkCompactCollector::StartSweepNewSpace() {
PagedSpaceForNewSpace* paged_space = heap_->paged_new_space()->paged_space();
paged_space->ClearAllocatorState();
int will_be_swept = 0;
heap_->StartResizeNewSpace();
DCHECK(empty_new_space_pages_to_be_swept_.empty());
for (auto it = paged_space->begin(); it != paged_space->end();) {
PageMetadata* p = *(it++);
DCHECK(p->SweepingDone());
DCHECK(!p->Chunk()->IsFlagSet(MemoryChunk::BLACK_ALLOCATED));
if (p->live_bytes() > 0) {
// Non-empty pages will be evacuated/promoted.
continue;
}
if (paged_space->ShouldReleaseEmptyPage()) {
ReleasePage(paged_space, p);
} else {
empty_new_space_pages_to_be_swept_.push_back(p);
}
will_be_swept++;
}
if (v8_flags.gc_verbose) {
PrintIsolate(heap_->isolate(),
"sweeping: space=%s initialized_for_sweeping=%d",
ToString(paged_space->identity()), will_be_swept);
}
}