GC3_MarkCompact

mark_compact.h/cc

virtual GcType GetGcType() const OVERRIDE {
    return kGcTypePartial;//MarkCompact不处理ImageSpace和ZygoteSpace
}
virtual CollectorType GetCollectorType() const OVERRIDE {
    return kCollectorTypeMC;
}

void MarkCompact::SetSpace(space::BumpPointerSpace* space) {
    space_ = space;//space_是MarkCompact成员变量
}

RunPhases

void MarkCompact::RunPhases() {
    Thread* self = Thread::Current();
    /* InitializePhase非常简单,其中需要注意的是MarkCompact下面两个成员变量的设置:
      (1) mark_stack_ = heap_->GetMarkStack();
      (2) mark_bitmap_ = heap_->GetMarkBitmap();
    */
    InitializePhase();
    {
        ScopedPause pause(this);//MarkCompact是stop-the-world类型的回收器
        ......
        MarkingPhase();//①标记阶段,详情见下文分析
        ReclaimPhase();//②回收阶段,详情见下文分析
    }
    ......
    FinishPhase();//收尾工作,非常简单,读者可自行阅读
}

MarkingPhase

void MarkCompact::MarkingPhase() {
    Thread* self = Thread::Current();
    /*MarkCompact基于Mark-Compact回收原理,所以它也需要标记能搜索到的对象。不过,由于
      BumpPointerSpace空间对象不包含位图对象,所以下面将为space_(指向一个
      BumpPointerSpace空间)创建一个位图对象objects_before_forwarding。它用于记录
      搜索到的对象。*/
    objects_before_forwarding_.reset(accounting::ContinuousSpaceBitmap::Create(
        "objects before forwarding", space_->Begin(), space_->Size()));
    //此外还创建了一个位图对象objects_with_lockword_,它和GC没有什么关系,只是用于
    //保存一些信息。下文将见到objects_with_lockword_的作用
    objects_with_lockword_.reset(accounting::ContinuousSpaceBitmap::Create(
        "objects with lock words", space_->Begin(), space_->Size()));

    //将ImageSpace或ZygoteSpace加到MarkCompact immune_space_容器中
    BindBitmaps();
    /*ProcessCards和ClearCardTable用于处理CardTable中对应的card。此处请读者注意,
      虽然MarkCompact也是通过移动对象来实现内存回收,但MarkCompact移动对象的过程是在
      最后的回收阶段。此时,所有的非垃圾对象都已经标记。所以,MarkCompact中可以使用Write
      Barrier来记录跨空间的对象引用。作为对比,ConcurrentCopying在标记阶段可能就会移动
      对象,这时就不方便使用Write Barrier了,而只能使用Read Barrier。  */
    heap_->ProcessCards(GetTimings(), false, false, true);
    heap_->GetCardTable()->ClearCardTable();
    //下面几个函数我们都介绍过
    if (kUseThreadLocalAllocationStack) {
        ......
        heap_->RevokeAllThreadLocalAllocationStacks(self);
    }
    ......
    heap_->SwapStacks();
    {
        WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
        MarkRoots();//搜索并标记根对象,详情见下文
        //借助CardTable来处理ImageSpace或ZygoteSpace中存在跨空间引用的对象,每找到
        //这样一个对象就对其做标记并压入mark_stack_中。读者可先了解上面的MarkRoots函数
        UpdateAndMarkModUnion();
        MarkReachableObjects();//从根对象出发,扫描它们所引用的对象
    }
    ......//Java Reference对象的处理等
}

ReclaimPhase

void MarkCompact::ReclaimPhase() {
    ......
    WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
    /*Sweep将回收除space_、immune_spaces_外其他空间对象中的垃圾。内部代码逻辑非常简单,
      就是调用ContinuousMemMapAllocSpace的Sweep函数进行回收。这些空间的垃圾回收使用
      的是Mark-Sweep方法,不是Mark-Compact。*/
    Sweep(false);
    //调用GarbageCollector SwapBitmaps函数,该函数在MarkSweep类中已经介绍过了
    SwapBitmaps();
    GetHeap()->UnBindBitmaps();//该函数在MarkSweep中已经介绍过了

    //压缩,这才是MarkCompact的精髓
    Compact();
}

Compact

图解
graph LR
CalculateObjectForwardingAddresses-->UpdateReferences-->MoveObjectsToForwardingAddress
void MarkCompact::Compact() {
    .....
    /*Compact中有三个关键函数,此处先简单介绍它们的作用:
     1:  CalculateObjectForwardingAddresses:计算每个存活对象的forwarding address。
      这个地址也就是这些对象的新的内存地址。
      2: UpdateReferences:更新对象的引用关系,将所引用的对象修改为对应的forwarding
      address。这个函数没有什么特殊的知识,读者可自行阅读。
      3:  MoveObjects:将对象移动到它的forwarding address处。  */
    CalculateObjectForwardingAddresses();
    UpdateReferences();
    MoveObjects();
    ......
    /*更新space_的末尾位置。经过上面压缩处理后,space_中的垃圾对象被清除,而非垃圾对象们
      又被移动到了一起。这些非垃圾对象在space_中的末尾位置由bump_pointer_标示。  */
    space_->SetEnd(bump_pointer_);
    //清零[bump_Pointer_,bump_pointer_+bytes_freed)这段空间。这段空间就是垃圾对象所
    //占据的内存大小
    memset(bump_pointer_, 0, bytes_freed);
}
CalculateObjectForwardingAddresses
//CalculateObjectForwardingAddress展示了MarkCompact中Compact的方法,就是将非垃圾对象一个一个排列起来。显然,要支持这种操作的话非BumpPointerSpace不可。
void MarkCompact::CalculateObjectForwardingAddresses() {
    ......
    //bump_pointer_初值为space_的起始位置
    bump_pointer_ = reinterpret_cast<uint8_t*>(space_->Begin());
    /*objects_before_forwarding_记录了space_中非垃圾对象的位图信息。下面的代码
      将遍历space_中的非垃圾对象,然后调用函数对象进行处理。
      CalculateObjectForwardingAddressVisitor内部调用MarkCompact ForwardObject
      对每一个非垃圾对象进行处理。我们直接来看ForwardObject。*/
    CalculateObjectForwardingAddressVisitor visitor(this);
    objects_before_forwarding_->VisitMarkedRange(
                    reinterpret_cast<uintptr_t>(space_->Begin()),
                    reinterpret_cast<uintptr_t>(space_->End()),
                    visitor);
}

void MarkCompact::ForwardObject(mirror::Object* obj) {
    //获取这个对象的所占内存的大小
    const size_t alloc_size = RoundUp(obj->SizeOf(), space::BumpPointerSpace::kAlignment);
    LockWord lock_word = obj->GetLockWord(false);
    /*如果这个obj之前有设置LockWord(可能代表一个用于线程同步的Monitor),下面的if代码将
      把LockWord旧值保存起来。等后续对象移动完毕后,我们需要恢复Obj的LockWord的旧值。  */
    if (!LockWord::IsDefault(lock_word)) {
        //objects_with_lockword_记录哪个对象存在LockWord的旧值
        objects_with_lockword_->Set(obj);
        //lock_words_to_restore_是一个stddqueue(双端队列),用于保存obj的
        //LockWord旧值
        lock_words_to_restore_.push_back(lock_word);
    }
    //设置obj的forwarding address,为bump_pointer_
    obj->SetLockWord(LockWord::FromForwardingAddress(reinterpret_cast<size_t>(bump_pointer_)),false);
    //移动bump_poionter_,使得它指向下一个对象的forwarding address
    bump_pointer_ += alloc_size;
    ++live_objects_in_space_;
}
UpdateReferences

……

MoveObjects
void MarkCompact::MoveObjects() {
    ......
    /*遍历存活对象,MoveObjectVisitor内部调用MoveObject函数进行处理,下面将直接介绍
      MoveObject的内容。*/
    MoveObjectVisitor visitor(this);//内部调用MoveObject
    objects_before_forwarding_->VisitMarkedRange(
                reinterpret_cast<uintptr_t>(space_->Begin()),
                reinterpret_cast<uintptr_t>(space_->End()),
                visitor);
    ......
}
void MarkCompact::MoveObject(mirror::Object* obj, size_t len) {
    //从LockWord中获取obj的目标地址
    uintptr_t dest_addr = obj->GetLockWord(false).ForwardingAddress();
    mirror::Object* dest_obj = reinterpret_cast<mirror::Object*>(dest_addr);
    //使用memmove将obj移动到dest_addr处。
    memmove(reinterpret_cast<void*>(dest_addr),
                            reinterpret_cast<const void*>(obj), len);
    LockWord lock_word = LockWord::Default();
    //如果obj之前有LockWord旧值,则需要从lock_words_to_restore_中拿到旧值
    if (UNLIKELY(objects_with_lockword_->Test(obj))) {
        lock_word = lock_words_to_restore_.front();
        lock_words_to_restore_.pop_front();
    }
    //设置dest_obj的LockWord。
    dest_obj->SetLockWord(lock_word, false);
}