class StickyMarkSweep final : public PartialMarkSweep {
public:
GcType GetGcType() const override {
return kGcTypeSticky;
}
StickyMarkSweep(Heap* heap, bool is_concurrent, const std::string& name_prefix = "");
~StickyMarkSweep() {}
void MarkConcurrentRoots(VisitRootFlags flags) override
REQUIRES(Locks::heap_bitmap_lock_)
REQUIRES(!mark_stack_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
protected:
// Bind the live bits to the mark bits of bitmaps for all spaces, all spaces other than the
// alloc space will be marked as immune.
void BindBitmaps() override REQUIRES_SHARED(Locks::mutator_lock_);
void MarkReachableObjects()
override
REQUIRES(Locks::heap_bitmap_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
void Sweep(bool swap_bitmaps)
override
REQUIRES(Locks::heap_bitmap_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
};
void StickyMarkSweep::BindBitmaps() {
PartialMarkSweep::BindBitmaps();
WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
// For sticky GC, we want to bind the bitmaps of all spaces as the allocation stack lets us
// know what was allocated since the last GC. A side-effect of binding the allocation space mark
// and live bitmap is that marking the objects will place them in the live bitmap.
for (const auto& space : GetHeap()->GetContinuousSpaces()) {
if (space->IsContinuousMemMapAllocSpace() &&
space->GetGcRetentionPolicy() == space::kGcRetentionPolicyAlwaysCollect) {
DCHECK(space->IsContinuousMemMapAllocSpace());
space->AsContinuousMemMapAllocSpace()->BindLiveToMarkBitmap();
}
}
for (const auto& space : GetHeap()->GetDiscontinuousSpaces()) {
CHECK(space->IsLargeObjectSpace());
space->AsLargeObjectSpace()->CopyLiveToMarked();
}
}
根据上文对MarkSweep GC代码逻辑的介绍可知,空间对象的live_bitmap_就是本次GC的集合Live。Heap mark_bitmap_为集合Mark。调用BindBitmaps的时候,标记工作还未开展,所以集合Mark为空(集合Mark在上次GC的FinishPhase中被清空)。对StickyMarkSweep来说,标记还没有开始做(BindBitmaps函数为GC的准备工作),我们就已经把上次GC的幸存对象“标记”好了。所以,上次GC的幸存对象在本次GC中将被保留
void ContinuousMemMapAllocSpace::BindLiveToMarkBitmap() {
CHECK(!HasBoundBitmaps());
temp_bitmap_ = std::move(mark_bitmap_);
mark_bitmap_.CopyView(live_bitmap_);
}
StickyMarkSweep ProcessCards 参数clear_alloc_space_cards为false
void MarkSweep::MarkingPhase() {
TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
Thread* self = Thread::Current();
BindBitmaps();
FindDefaultSpaceBitmap();
heap_->ProcessCards(GetTimings(),
/* use_rem_sets= */ false,
/* process_alloc_space_cards= */ true,
/* clear_alloc_space_cards= */ GetGcType() != kGcTypeSticky);
WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
MarkRoots(self);
MarkReachableObjects();
// Pre-clean dirtied cards to reduce pauses.
PreCleanCards();
}
在StickyMarkSweep->MarkReachableObjects中,mark_stack_被清空。StickyMarkSweep需要往mark_stack_填充自己的内容(MarkRoots往mark_stack_填充的对象算MarkSweep的)—该工作由下面的ScanGrayObjects完成。ScanGrayObjects的功能很简单:
(1)遍历Heap->continuous_spaces_中的空间对象。每找到一个mark_bitmap_不为空指针的空间对象,就转到2去执行。
(2)调用Heap->card_table_的Scan函数。找到那些card值大于或等于minimum_age的card,然后根据这个card再到空间对象去找到对应的mirror Object对象。注意,这些对象必须是在空间对象mark_bitmap_所标记过了的。
(3)每找到这样的一个mirror Object对象就调用MarkSweep的ScanObject以标记它的引用型成员变量。ScanObject内部会调用MarkSweep->MarkObject进行标记处理。
void StickyMarkSweep::MarkReachableObjects() {
// All reachable objects must be referenced by a root or a dirty card, so we can clear the mark
// stack here since all objects in the mark stack will get scanned by the card scanning anyways.
// TODO: Not put these objects in the mark stack in the first place.
mark_stack_->Reset();
RecursiveMarkDirtyObjects(false, accounting::CardTable::kCardDirty - 1);
}
void MarkSweep::RecursiveMarkDirtyObjects(bool paused, uint8_t minimum_age) {
ScanGrayObjects(paused, minimum_age);
ProcessMarkStack(paused);
}
StickyMarkSweep->MarkReachableObjects决定了集合Mark的内容,但还没有确定集合Live。
- 集合Live:来自Heap->live_stack_。它保存了两次GC间所创建的对象。
- 集合Mark:上次GC所留存的对象均为标记过的对象。另外,它们当中凡是修改了引用型成员变量的对象都会被遍历,并且要被标记。
void StickyMarkSweep::Sweep(bool swap_bitmaps ATTRIBUTE_UNUSED) {
SweepArray(GetHeap()->GetLiveStack(), false);
}
(1) 用于保存本次GC要清理的Space
(2) non_moving_space存在垃圾对象的概率小,如果存在non_moving_space,则将其加到数组的最后
void MarkSweep::SweepArray(accounting::ObjectStack* allocations, bool swap_bitmaps) {
TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
Thread* self = Thread::Current();
mirror::Object** chunk_free_buffer = reinterpret_cast<mirror::Object**>(
sweep_array_free_buffer_mem_map_.BaseBegin());
size_t chunk_free_pos = 0;
ObjectBytePair freed;
ObjectBytePair freed_los;
// How many objects are left in the array, modified after each space is swept.
StackReference<mirror::Object>* objects = allocations->Begin();
size_t count = allocations->Size();
// Change the order to ensure that the non-moving space last swept as an optimization.
std::vector<space::ContinuousSpace*> sweep_spaces;
space::ContinuousSpace* non_moving_space = nullptr;
//(1) start
for (space::ContinuousSpace* space : heap_->GetContinuousSpaces()) {
if (space->IsAllocSpace() &&
!immune_spaces_.ContainsSpace(space) &&
space->GetLiveBitmap() != nullptr) {
if (space == heap_->GetNonMovingSpace()) {
non_moving_space = space;
} else {
sweep_spaces.push_back(space);
}
}
}
//(1) end
// Unlikely to sweep a significant amount of non_movable objects, so we do these after
// the other alloc spaces as an optimization.
if (non_moving_space != nullptr) {
sweep_spaces.push_back(non_moving_space);
}
// Start by sweeping the continuous spaces.
for (space::ContinuousSpace* space : sweep_spaces) {
space::AllocSpace* alloc_space = space->AsAllocSpace();
accounting::ContinuousSpaceBitmap* live_bitmap = space->GetLiveBitmap();
accounting::ContinuousSpaceBitmap* mark_bitmap = space->GetMarkBitmap();
if (swap_bitmaps) {
std::swap(live_bitmap, mark_bitmap);
}
StackReference<mirror::Object>* out = objects;
for (size_t i = 0; i < count; ++i) {
mirror::Object* const obj = objects[i].AsMirrorPtr();
if (kUseThreadLocalAllocationStack && obj == nullptr) {
continue;
}
if (space->HasAddress(obj)) {
// This object is in the space, remove it from the array and add it to the sweep buffer
// if needed.
if (!mark_bitmap->Test(obj)) {
if (chunk_free_pos >= kSweepArrayChunkFreeSize) {
TimingLogger::ScopedTiming t2("FreeList", GetTimings());
freed.objects += chunk_free_pos;
freed.bytes += alloc_space->FreeList(self, chunk_free_pos, chunk_free_buffer);
chunk_free_pos = 0;
}
chunk_free_buffer[chunk_free_pos++] = obj;
}
} else {
(out++)->Assign(obj);
}
}
if (chunk_free_pos > 0) {
TimingLogger::ScopedTiming t2("FreeList", GetTimings());
freed.objects += chunk_free_pos;
freed.bytes += alloc_space->FreeList(self, chunk_free_pos, chunk_free_buffer);
chunk_free_pos = 0;
}
// All of the references which space contained are no longer in the allocation stack, update
// the count.
count = out - objects;
}
// Handle the large object space.
space::LargeObjectSpace* large_object_space = GetHeap()->GetLargeObjectsSpace();
if (large_object_space != nullptr) {
accounting::LargeObjectBitmap* large_live_objects = large_object_space->GetLiveBitmap();
accounting::LargeObjectBitmap* large_mark_objects = large_object_space->GetMarkBitmap();
if (swap_bitmaps) {
std::swap(large_live_objects, large_mark_objects);
}
for (size_t i = 0; i < count; ++i) {
mirror::Object* const obj = objects[i].AsMirrorPtr();
// Handle large objects.
if (kUseThreadLocalAllocationStack && obj == nullptr) {
continue;
}
if (!large_mark_objects->Test(obj)) {
++freed_los.objects;
freed_los.bytes += large_object_space->Free(self, obj);
}
}
}
{
TimingLogger::ScopedTiming t2("RecordFree", GetTimings());
RecordFree(freed);
RecordFreeLOS(freed_los);
t2.NewTiming("ResetStack");
allocations->Reset();
}
sweep_array_free_buffer_mem_map_.MadviseDontNeedAndZero();
}