[原文出處------------ART運行時Mark-Compact( MC)GC執行過程分析](http://blog.csdn.net/luoshengyang/article/details/45162589)
除了Semi-Space(SS)GC和Generational Semi-Space(GSS)GC,ART運行時還引入了第三種Compacting GC:Mark-Compact(MC)GC。這三種GC雖然都是Compacting GC,不過它們的實現方式卻有很大不同。SS GC和GSS GC需兩個Space來壓縮內存,而MC GC只需一個Space來壓縮內存。本文就詳細分析MC GC的執行過程。
從前面[ART運行時Semi-Space(SS)和Generational Semi-Space(GSS)GC執行過程分析](http://blog.csdn.net/luoshengyang/article/details/45017207)一文可以知道,Mark-Compact GC主要是針對ART運行時正在使用的Bump Pointer Space進行壓縮,如圖1所示:

圖1 Mark-Compact GC的執行過程
從圖1可以看出,當Mark-Compact GC執行完成之后,原來位于Bump Pointer Space上的仍然存活的對象會被依次移動至原Bump Pointer Space的左側,并且按地址從小到大緊湊地排列在一起。這個過程不需要借助于額外的Space來完成。這一點是Mark-Compact GC與Semi-Space GC、Generational Semi-Space GC的顯著區別。
不過,Mark-Compact GC與Semi-Space GC、Generational Semi-Space GC一樣,除了需要對ART運行時當前使用的Bump Pointer Space進行內在壓縮之外,還需要修改其它Space對Bump Pointer Space的引用,因為Bump Pointer Space的對象發生了移動。此外,ART運行時堆的Non Moving Space和Large Object Space也會進行像Mark-Sweep GC一樣的垃圾回收。
從前面[ART運行時Semi-Space(SS)和Generational Semi-Space(GSS)GC執行過程分析](http://blog.csdn.net/luoshengyang/article/details/45017207)一文還可以知道,在ART運行時內部,所有的GC都是通過Heap類的成員函數CollectGarbageInternal開始執行的,并且當決定要執行Mark-Compact GC時,最終會以MarkCompact類的成員函數RunPhases作為入口點,如下所示:
~~~
void MarkCompact::RunPhases() {
Thread* self = Thread::Current();
InitializePhase();
CHECK(!Locks::mutator_lock_->IsExclusiveHeld(self));
{
ScopedPause pause(this);
......
MarkingPhase();
ReclaimPhase();
}
......
FinishPhase();
}
~~~
這個函數定義在文件art/runtime/gc/collector/mark_compact.cc中。
與Semi-Space GC、Generational Semi-Space GC一樣,Mark-Compact GC的執行過程也分為初始化、標記、回收和結束四個階段,對應的函數分別為MarkCompact類的成員函數InitializePhase、MarkingPhase、ReclaimPhase和FinishPhase。其中,標記和回收階段是在掛起其它的ART運行時線程的前提下進行的。注意,掛起其它的ART運行時線程的操作通過ScopedPause類的構造函數實現的。當標記和回收階段結束,ScopedPause類的析構函數就會自動恢復之前被掛起的ART運行時線程。
接下來,我們就分別分析Mark-Compact GC的四個階段的執行過程,即MarkCompact類的成員函數InitializePhase、MarkingPhase、ReclaimPhase和FinishPhase的實現。
Mark-Compact GC的初始化階段由MarkCompact類的成員函數InitializePhase實現,如下所示:
~~~
void MarkCompact::InitializePhase() {
TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
mark_stack_ = heap_->GetMarkStack();
......
immune_region_.Reset();
......
// TODO: I don't think we should need heap bitmap lock to Get the mark bitmap.
ReaderMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
mark_bitmap_ = heap_->GetMarkBitmap();
live_objects_in_space_ = 0;
}
~~~
這個函數定義在文件art/runtime/gc/collector/mark_compact.cc中。
MarkCompact類的成員函數InitializePhase主要就是執行一些初始化工作,例如獲得ART運行時堆的Mark Stack、Mark Bitmap,保存在成員變量mark_stack_和mark_bitmap_中,并且重置MarkCompact類的成員變量immune_region_描述的一個不進行垃圾回收的Space區間為空,以及將成員變量live_objects_in_space_的值置為0。MarkCompact類的成員變量live_objects_in_space_用來描述Mark-Compact GC執先完成后,Bump Pointer Space還有多少對象是存活的。
Mark-Compact GC的標記階段來MarkCompact類的成員函數MarkingPhase實現,如下所示:
~~~
void MarkCompact::MarkingPhase() {
TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
Thread* self = Thread::Current();
// Bitmap which describes which objects we have to move.
objects_before_forwarding_.reset(accounting::ContinuousSpaceBitmap::Create(
"objects before forwarding", space_->Begin(), space_->Size()));
// Bitmap which describes which lock words we need to restore.
objects_with_lockword_.reset(accounting::ContinuousSpaceBitmap::Create(
"objects with lock words", space_->Begin(), space_->Size()));
CHECK(Locks::mutator_lock_->IsExclusiveHeld(self));
// Assume the cleared space is already empty.
BindBitmaps();
t.NewTiming("ProcessCards");
// Process dirty cards and add dirty cards to mod-union tables.
heap_->ProcessCards(GetTimings(), false);
// Clear the whole card table since we can not Get any additional dirty cards during the
// paused GC. This saves memory but only works for pause the world collectors.
t.NewTiming("ClearCardTable");
heap_->GetCardTable()->ClearCardTable();
// Need to do this before the checkpoint since we don't want any threads to add references to
// the live stack during the recursive mark.
if (kUseThreadLocalAllocationStack) {
t.NewTiming("RevokeAllThreadLocalAllocationStacks");
heap_->RevokeAllThreadLocalAllocationStacks(self);
}
t.NewTiming("SwapStacks");
heap_->SwapStacks(self);
{
WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
MarkRoots();
// Mark roots of immune spaces.
UpdateAndMarkModUnion();
// Recursively mark remaining objects.
MarkReachableObjects();
}
ProcessReferences(self);
{
ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
SweepSystemWeaks();
}
// Revoke buffers before measuring how many objects were moved since the TLABs need to be revoked
// before they are properly counted.
RevokeAllThreadLocalBuffers();
......
}
~~~
這個函數定義在文件art/runtime/gc/collector/mark_compact.cc中。
MarkCompact類的成員函數MarkingPhase的執行過程如下所示:
1. 針對當前要進行Mark-Compact的Bump Pointer Space,創建兩個ContinuousSpaceBitmap,分別保存在MarkCompact類的成員變量objects_before_forwarding_和objects_with_lockword_。其中,前者用來記錄當前要進行Mark-Compact的Bump Pointer Space的存活對象,而后者用來記錄上述的存活對象在移動前它們的LockWord有沒有被覆蓋。如果被覆蓋了,那么在它們移動之后,需要恢復它們之前的LockWord。后面我們就可以看到,Mark-Compact GC在移動對象的時候,會先計算出每一個需要移動的對象的新地址,并且將該新地址作為一個Forwarding Address記錄它的LockWord中。因此,當對象移動到新地址后,就需要恢復它們之前的LockWord值。
2. 調用MarkCompact類的成員函數BindBitmaps確定哪些Space是不需要進行垃圾回收的。
3. 調用Heap類的成員函數ProcessCards處理Dirty Card,即將它們記錄在對應的Mod Union Table中,以便后面可以找到上次GC以來,不需要進行垃圾回收的Space對需要垃圾回收的Space的引用情況。
4. 調用CardTable類的成員函數ClearCardTable清零Dirty Card。因為Dirty Card在經過上一步的操作之后,已經記錄在了對應的Mod Union Table,因此現在不需要它們了。
5. 如果ART運行時堆使用了線程局部Allocation Stack,即在常量kUseThreadLocalAllocationStack等于true的情況下,調用Heap類的成員函數RevokeAllThreadLocalAllocationStacks對它們進行回收。
6. 調用Heap類的成員函數SwapStacks交換ART運行時堆的Allocation Stack和Live Stack。
7. 調用MarkCompact類的成員函數MarkRoots標記根集對象。
8. 調用MarkCompact類的成員函數UpdateAndMarkModUnion標記Dirty Card引用的對象。
9. 調用MarkCompact類的成員函數MarkReachableObjects標記可達對象,即遞歸標記根集對象和Dirty Card引用的對象可達的對象。
10. 調用MarkCompact類的成員函數ProcessReferences處理引用類型的對象,即Soft Reference、Weak Reference、Phantom Reference和Finalizer Reference對象。
11. 調用MarkCompact類的成員函數SweepSystemWeaks處理那些沒有被標記的常量字符串、Monitor對象和在JNI創建的全局弱引用對象等。
12. 調用MarkCompact類的成員函數RevokeAllThreadLocalBuffers回收各個ART運行時線程的局部分配緩沖區。
在上述的操作中,我們主要是分析第2、7、8和9操作,即MarkCompact類的成員函數BindBitmaps、MarkRoots、UpdateAndMarkModUnion和MarkReachableObjects的實現、其它的操作可以參考[ART運行時垃圾收集(GC)過程分析](http://blog.csdn.net/luoshengyang/article/details/42555483)或者[ART運行時Semi-Space(SS)和Generational Semi-Space(GSS)GC執行過程分析](http://blog.csdn.net/luoshengyang/article/details/45017207)一文。
MarkCompact類的成員函數BindBitmaps的實現如下所示:
~~~
void MarkCompact::BindBitmaps() {
TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
// Mark all of the spaces we never collect as immune.
for (const auto& space : GetHeap()->GetContinuousSpaces()) {
if (space->GetGcRetentionPolicy() == space::kGcRetentionPolicyNeverCollect ||
space->GetGcRetentionPolicy() == space::kGcRetentionPolicyFullCollect) {
CHECK(immune_region_.AddContinuousSpace(space)) << "Failed to add space " << *space;
}
}
}
~~~
這個函數定義在文件art/runtime/gc/collector/mark_compact.cc中。
在前面[ART運行時Semi-Space(SS)和Generational Semi-Space(GSS)GC執行過程分析](http://blog.csdn.net/luoshengyang/article/details/45017207)這篇文章提到,在ART運行時中,回收策略為kGcRetentionPolicyNeverCollect和kGcRetentionPolicyFullCollect的Space是Image Space和Zygote Space,因此,從這里可以看出,在Mark-Compact GC中,Image Space和Zygote Space是不進行垃圾回收的,同時也意味著Non Moving Space、Bump Pointer Space和Large Object Space需要進行垃圾回收。
MarkCompact類的成員函數MarkRoots的實現如下所示:
~~~
void MarkCompact::MarkRoots() {
TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
Runtime::Current()->VisitRoots(MarkRootCallback, this);
}
~~~
這個函數定義在文件art/runtime/gc/collector/mark_compact.cc中。
MarkCompact類的成員函數MarkRoots調用Runtime類的成員函數VisitRoots遍歷當前的根集對象,并且對于每一個根集對象,都調用MarkCompact類的靜態成員函數MarkRootCallback進行標記處理。
MarkCompact類的靜態成員函數MarkRootCallback的實現如下所示:
~~~
void MarkCompact::MarkRootCallback(Object** root, void* arg, uint32_t /*thread_id*/,
RootType /*root_type*/) {
reinterpret_cast<MarkCompact*>(arg)->MarkObject(*root);
}
~~~
這個函數定義在文件art/runtime/gc/collector/mark_compact.cc中。
MarkCompact類的靜態成員函數MarkRootCallback又是通過調用另外一個成員函數MarkObject來標記根集對象,如下所示:
~~~
inline void MarkCompact::MarkObject(mirror::Object* obj) {
......
if (immune_region_.ContainsObject(obj)) {
return;
}
if (objects_before_forwarding_->HasAddress(obj)) {
if (!objects_before_forwarding_->Set(obj)) {
MarkStackPush(obj); // This object was not previously marked.
}
} else {
......
BitmapSetSlowPathVisitor visitor;
if (!mark_bitmap_->Set(obj, visitor)) {
// This object was not previously marked.
MarkStackPush(obj);
}
}
}
~~~
這個函數定義在文件art/runtime/gc/collector/mark_compact.cc中。
MarkCompact類的成員函數MarkObject首先判斷對象obj是否位于非垃圾回收空間中。如果是的話,那么不用對它進行處理了。
MarkCompact類的成員函數MarkObject接著通過成員變量objects_before_forwarding_指向的一個ContinuousSpaceBitmap來判斷對象obj是否位于要進行垃圾回收和對象壓縮的Bump Pointer Space中。如果是的話,再將其在上述的ContinuousSpaceBitmap的對應位設置為1。此外,如果對象obj是第一次被標記,那么它還被壓入到Mark Stack中去,以便后面可以繼續對它引用的其它對象進行遞歸標記處理。
如果對象obj不是位于要行垃圾回收和對象壓縮的Bump Pointer Space,那么這時候它肯定就是在Non Moving Space和Large Object Space中,這時候就直接對象在Mark Bitmap上對應的位設置為1。同樣,如果對象是第一次被標記,那么也會被壓入到Mark Stack中。
根集對象標記完成之后,接下來再標記Dirty Card引用的對象,這是通過調用MarkCompact類的成員函數UpdateAndMarkModUnion實現的,如下所示:
~~~
void MarkCompact::UpdateAndMarkModUnion() {
TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
for (auto& space : heap_->GetContinuousSpaces()) {
// If the space is immune then we need to mark the references to other spaces.
if (immune_region_.ContainsSpace(space)) {
accounting::ModUnionTable* table = heap_->FindModUnionTableFromSpace(space);
if (table != nullptr) {
// TODO: Improve naming.
TimingLogger::ScopedTiming t(
space->IsZygoteSpace() ? "UpdateAndMarkZygoteModUnionTable" :
"UpdateAndMarkImageModUnionTable", GetTimings());
table->UpdateAndMarkReferences(MarkHeapReferenceCallback, this);
}
}
}
}
~~~
這個函數定義在文件art/runtime/gc/collector/mark_compact.cc中。
由于在Mark-Compact GC中,只有Image Space和Zygote Space是不需要進行垃圾回收的,因此這里就僅僅對它們進行處理。在前面[ART運行時Semi-Space(SS)和Generational Semi-Space(GSS)GC執行過程分析](http://blog.csdn.net/luoshengyang/article/details/45017207)這篇文章提到,Image Space和Zygote Space都是有一個關聯的Mod Union Table,并且通過調用這個Mod Union Table的成員函數UpdateAndMarkReferences來處理Dirty Card引用的對象。
對于Dirty Card引用的每一個對象,即Dirty Card記錄的上次GC以來有修改過引用類型的成員變量的對象,都會被MarkCompact類的靜態成員函數MarkHeapReferenceCallback進行標記,如下所示:
~~~
void MarkCompact::MarkHeapReferenceCallback(mirror::HeapReference<mirror::Object>* obj_ptr,
void* arg) {
reinterpret_cast<MarkCompact*>(arg)->MarkObject(obj_ptr->AsMirrorPtr());
}
~~~
這個函數定義在文件art/runtime/gc/collector/mark_compact.cc中。
從這里就可以看出,Dirty Card引用的對象與根集對象一樣,都是通過MarkCompact類的成員函數MarkObject進行標記的。
Dirty Card引用的對象與根集對象都標記完成之后,就開始標記它們可達的對象了,這是通過調用MarkCompact類的成員函數MarkReachableObjects來實現的,如下所示:
~~~
void MarkCompact::MarkReachableObjects() {
TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
accounting::ObjectStack* live_stack = heap_->GetLiveStack();
{
TimingLogger::ScopedTiming t2("MarkAllocStackAsLive", GetTimings());
heap_->MarkAllocStackAsLive(live_stack);
}
live_stack->Reset();
// Recursively process the mark stack.
ProcessMarkStack();
}
~~~
這個函數定義在文件art/runtime/gc/collector/mark_compact.cc中。
與Semi-Space GC和Generational Semi-Space GC一樣,在遞歸標記根集對象和Dirty Card引用的對象的可達對象之前,首先會將保存在Allocation Stack里面的對象的Live Bitmap位設置為1。
接下來,MarkCompact類的成員函數MarkReachableObjects調用另外一個成員函數ProcessMarkStack來遞歸標記根集對象和Dirty Card引用的對象的可達對象,后者的實現如下所示:
~~~
void MarkCompact::ProcessMarkStack() {
TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
while (!mark_stack_->IsEmpty()) {
Object* obj = mark_stack_->PopBack();
DCHECK(obj != nullptr);
ScanObject(obj);
}
}
~~~
這個函數定義在文件art/runtime/gc/collector/mark_compact.cc中。
MarkCompact類的成員函數ProcessMarkStack逐個地將Mark Stack的對象彈出來,并且調用另外一個成員函數ScanObject對它們的引用類型的成員變量進行標記。注意, MarkCompact類的成員函數ScanObject在標記對象的過程中,也會可能壓入新的對象到Mark Stack中,因此這是一個遞歸標記的過程。
MarkCompact類的成員函數ScanObject的實現如下所示:
~~~
void MarkCompact::ScanObject(Object* obj) {
MarkCompactMarkObjectVisitor visitor(this);
obj->VisitReferences<kMovingClasses>(visitor, visitor);
}
~~~
這個函數定義在文件art/runtime/gc/collector/mark_compact.cc中。
從這里可以看到,對象obj的引用類型的成員變量引用的對象是通過MarkCompactMarkObjectVisitor類來進行標記的,如下所示:
~~~
class MarkCompactMarkObjectVisitor {
public:
explicit MarkCompactMarkObjectVisitor(MarkCompact* collector) : collector_(collector) {
}
void operator()(Object* obj, MemberOffset offset, bool /*is_static*/) const ALWAYS_INLINE
EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::heap_bitmap_lock_) {
// Object was already verified when we scanned it.
collector_->MarkObject(obj->GetFieldObject<mirror::Object, kVerifyNone>(offset));
}
void operator()(mirror::Class* klass, mirror::Reference* ref) const
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) {
collector_->DelayReferenceReferent(klass, ref);
}
private:
MarkCompact* const collector_;
};
~~~
這個類定義在文件art/runtime/gc/collector/mark_compact.cc中。
MarkCompactMarkObjectVisitor類有兩個版本的符號重載成員函數()。其中,上面一個用來處理那些指向了普通對象的成員變量,而下面一個用來處理指向了引用對象的成員變量。其中,普通對象通過前面分析過的MarkCompact類的成員函數MarkObject進行標記,而引用對象則通過MarkCompact類的成員函數DelayReferenceReferent延遲進行處理。注意,從前面分析的MarkCompact類的成員函數MarkingPhase可以知道,上述的引用對象在遞歸標記可達對象結束之后,會通過MarkCompact類的成員函數ProcessReferences進行處理。
這一步完成之后,Mark-Compact GC的標記階段就執行完成了。注意,與Semi-Space GC和Generational Semi-Space GC不一樣,Mark-Compact GC在標記階段并沒有對象Bump Pointer Space的存活對象進行移動,而是在接下來的回收階段再執行此操作。
前面提到,Mark-Compact GC的回收階段是通過調用MarkCompact類的成員函數ReclaimPhase來執行的。因此,接下來我們就繼續分析MarkCompact類的成員函數ReclaimPhase的實現,如下所示:
~~~
void MarkCompact::ReclaimPhase() {
TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
// Reclaim unmarked objects.
Sweep(false);
// Swap the live and mark bitmaps for each space which we modified space. This is an
// optimization that enables us to not clear live bits inside of the sweep. Only swaps unbound
// bitmaps.
SwapBitmaps();
GetHeap()->UnBindBitmaps(); // Unbind the live and mark bitmaps.
Compact();
}
~~~
這個函數定義在文件art/runtime/gc/collector/mark_compact.cc中。
MarkCompact類的成員函數ReclaimPhase首先調用成員函數Sweep回收Non Moving Space和Large Object Space的垃圾,接著再調用成員函數SwapBitmaps交換ART運行時的Live Bitmap和Mark Bitmap。由于在回收垃圾之后,Live Bitmap和Mark Bitmap就沒有什么用了,因此這時候MarkCompact類的成員函數ReclaimPhase還會調用Heap類的成員函數UnBindBitmaps清零各個Space的Live Bitmap和Mark Bitmap,以便下次GC時可以直接使用。
最后,MarkCompact類的成員函數ReclaimPhase調用成員函數Compact對Bump Pointer Space的存活對象進行移動壓縮,并且修改引用了這些被移動對象的引用,它的實現如下所示:
~~~
void MarkCompact::Compact() {
TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
CalculateObjectForwardingAddresses();
UpdateReferences();
MoveObjects();
// Space
int64_t objects_freed = space_->GetObjectsAllocated() - live_objects_in_space_;
int64_t bytes_freed = reinterpret_cast<int64_t>(space_->End()) -
reinterpret_cast<int64_t>(bump_pointer_);
t.NewTiming("RecordFree");
space_->RecordFree(objects_freed, bytes_freed);
RecordFree(ObjectBytePair(objects_freed, bytes_freed));
space_->SetEnd(bump_pointer_);
// Need to zero out the memory we freed. TODO: Use madvise for pages.
memset(bump_pointer_, 0, bytes_freed);
}
~~~
這個函數定義在文件art/runtime/gc/collector/mark_compact.cc中。
MarkCompact類的成員函數Compact完成了以下三個重要的操作之后,再統計Mark-Compact GC釋放的對象數和內存字節數:
1. 調用MarkCompact類的成員函數CalculateObjectForwardingAddresses計算每一個將要被移動的對象要被移動到的新地址。
2. 調用MarkCompact類的成員函數UpdateReferences引用那些引用了被移動對象的引用,因為這時候被移動對象的新地址已經確定了。
3. 調用MarkCompact類的成員函數MoveObjects將要被移動的對象移動到前面計算好的新地址中。
為了更好地理解Mark-Compact GC,接下來我們繼續對上述提到的MarkCompact類的三個成員函數的實現進行分析。
MarkCompact類的成員函數CalculateObjectForwardingAddresses的實現如下所示:
~~~
void MarkCompact::CalculateObjectForwardingAddresses() {
TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
// The bump pointer in the space where the next forwarding address will be.
bump_pointer_ = reinterpret_cast<byte*>(space_->Begin());
// Visit all the marked objects in the bitmap.
CalculateObjectForwardingAddressVisitor visitor(this);
objects_before_forwarding_->VisitMarkedRange(reinterpret_cast<uintptr_t>(space_->Begin()),
reinterpret_cast<uintptr_t>(space_->End()),
visitor);
}
~~~
這個函數定義在文件art/runtime/gc/collector/mark_compact.cc中。
MarkCompact類的成員函數CalculateObjectForwardingAddresses首先是獲得當前正在處理的Bump Pointer Space的起始地址,并且保存在成員變量bump_pointer_中,接下來再通過CalculateObjectForwardingAddressVisitor類的操作符重載函數()來處理每一個在當前正在處理的Bump Pointer Space上分配的、并且仍然存活的對象。
CalculateObjectForwardingAddressVisitor類的操作符重載函數()的實現如下所示:
~~~
class CalculateObjectForwardingAddressVisitor {
public:
explicit CalculateObjectForwardingAddressVisitor(MarkCompact* collector)
: collector_(collector) {}
void operator()(mirror::Object* obj) const EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_,
Locks::heap_bitmap_lock_) {
......
collector_->ForwardObject(obj);
}
private:
MarkCompact* const collector_;
};
~~~
這個函數定義在文件art/runtime/gc/collector/mark_compact.cc中。
CalculateObjectForwardingAddressVisitor類的操作符重載函數()調用MarkCompact類的成員函數ForwardObject來計算對象obj移動后的新地址,它的實現如下所示:
~~~
void MarkCompact::ForwardObject(mirror::Object* obj) {
const size_t alloc_size = RoundUp(obj->SizeOf(), space::BumpPointerSpace::kAlignment);
LockWord lock_word = obj->GetLockWord(false);
// If we have a non empty lock word, store it and restore it later.
if (lock_word.GetValue() != LockWord().GetValue()) {
// Set the bit in the bitmap so that we know to restore it later.
objects_with_lockword_->Set(obj);
lock_words_to_restore_.push_back(lock_word);
}
obj->SetLockWord(LockWord::FromForwardingAddress(reinterpret_cast<size_t>(bump_pointer_)),
false);
bump_pointer_ += alloc_size;
++live_objects_in_space_;
}
~~~
這個函數定義在文件art/runtime/gc/collector/mark_compact.cc中。
MarkCompact類的成員函數ForwardObject首先是獲得對象obj的大小alloc_size,接著再判斷它的LockWord是否不等于空。如果不等于空的話,就將其在MarkCompact類的成員變量objects_with_lockword_描述的一個ContinuousSpaceBitmap的對應位設置為1,并且將該LockWord保存在MarkCompact類的成員變量lock_words_to_restore_描述的一個隊列中。
從前面[ART運行時Compacting GC簡要介紹和學習計劃](http://blog.csdn.net/luoshengyang/article/details/44513977)一文可以知道,一個對象的LockWord描述了該對象的狀態信息,例如鎖狀態、Hash值以及Forwarding Address等。由于接下來我們要將對象obj移動后的新地址記錄在它的LockWord中,也就是要借它的LockWord來用,因此當對象obj原來的LockWord不等于空的情況下,就需要先將它保存起來,以便對象obj移動完成之后,可以恢復原來的LockWord。
在Mark-Compact GC中,下一個對象要移動至的地址永遠記錄在MarkCompact類的成員變量bump_pointer_中,因此通過MarkCompact類的成員變量bump_pointer_就可以得到對象obj要移動至的地址。由于對象obj使用了當前MarkCompact類的成員變量bump_pointer_的值,因此我們需要更新它的值,即需要加上對象obj的大小,這樣就可以使得它永遠指向下一個要移動的對象的新地址。
回到MarkCompact類的成員函數CalculateObjectForwardingAddresses中,當它執行完成之后,在當前正在處理的Bump Pointer Space上分配的、并且仍然活著的對象的新地址就計算完畢,即都已經保存在它們自己的LockWord中,接下來就可以調用MarkCompact類的成員函數UpdateReferences來更新其它Space對當前正在處理的Bump Pointer Space的引用了。
MarkCompact類的成員函數UpdateReferences的實現如下所示:
~~~
void MarkCompact::UpdateReferences() {
TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
Runtime* runtime = Runtime::Current();
// Update roots.
runtime->VisitRoots(UpdateRootCallback, this);
// Update object references in mod union tables and spaces.
for (const auto& space : heap_->GetContinuousSpaces()) {
// If the space is immune then we need to mark the references to other spaces.
accounting::ModUnionTable* table = heap_->FindModUnionTableFromSpace(space);
if (table != nullptr) {
// TODO: Improve naming.
TimingLogger::ScopedTiming t(
space->IsZygoteSpace() ? "UpdateZygoteModUnionTableReferences" :
"UpdateImageModUnionTableReferences",
GetTimings());
table->UpdateAndMarkReferences(&UpdateHeapReferenceCallback, this);
} else {
// No mod union table, so we need to scan the space using bitmap visit.
// Scan the space using bitmap visit.
accounting::ContinuousSpaceBitmap* bitmap = space->GetLiveBitmap();
if (bitmap != nullptr) {
UpdateObjectReferencesVisitor visitor(this);
bitmap->VisitMarkedRange(reinterpret_cast<uintptr_t>(space->Begin()),
reinterpret_cast<uintptr_t>(space->End()),
visitor);
}
}
}
CHECK(!kMovingClasses)
<< "Didn't update large object classes since they are assumed to not move.";
// Update the system weaks, these should already have been swept.
runtime->SweepSystemWeaks(&MarkedForwardingAddressCallback, this);
// Update the objects in the bump pointer space last, these objects don't have a bitmap.
UpdateObjectReferencesVisitor visitor(this);
objects_before_forwarding_->VisitMarkedRange(reinterpret_cast<uintptr_t>(space_->Begin()),
reinterpret_cast<uintptr_t>(space_->End()),
visitor);
// Update the reference processor cleared list.
heap_->GetReferenceProcessor()->UpdateRoots(&MarkedForwardingAddressCallback, this);
}
~~~
這個函數定義在文件art/runtime/gc/collector/mark_compact.cc中。
在分析MarkCompact類的成員函數UpdateReferences的實現之前,我們首先要明確有哪些Space的對象引用了當前正在處理的Bump Pointer Space的對象。從前面[ART運行時Compacting GC堆創建過程分析](http://blog.csdn.net/luoshengyang/article/details/44789295)一文可以知道,Mark-Compact GC使用的Space有Image Space、Zygote Space、Non-Moving Space、Bump Pointer Space和Large Object Space。因此,在這些Space上分配的對象都有可能對當前正在處理的Bump Pointer Space的對象產生引用。此外,還有三類對象可能會對當前正在處理的Bump Pointer Space產生引用,那就是根集對象、ART運行時內部分配的對象以及那些特殊處理的引用對象。
對于根集對象,我們只需要調用Runtime類的成員函數VisitRoots重新遍歷一下它們,并且對于每一個根集對象,都調用MarkCompact類的靜態成員函數UpdateRootCallback來修改它們對當前正在處理的Bump Pointer Space的引用,如下所示:
~~~
void MarkCompact::UpdateRootCallback(Object** root, void* arg, uint32_t /*thread_id*/,
RootType /*root_type*/) {
mirror::Object* obj = *root;
mirror::Object* new_obj = reinterpret_cast<MarkCompact*>(arg)->GetMarkedForwardAddress(obj);
if (obj != new_obj) {
*root = new_obj;
DCHECK(new_obj != nullptr);
}
}
~~~
這個函數定義在文件art/runtime/gc/collector/mark_compact.cc中。
參數root描述的就是在當前調用棧上的、引用了根集對象的一個Slot。MarkCompact類的靜態成員函數UpdateRootCallback首先是調用成員函數GetMarkedForwardAddress檢查被引用的根集對象是否設置有Forward Address。如果設置有的話,就說明對應的調用棧Slot引用了當前正在處理的Bump Pointer Space的對象,因此這時候就需要修改該調用棧Slot的值,使得它引用的是移動后的根集對象。
MarkCompact類的成員函數GetMarkedForwardAddress的實現如下所示:
~~~
inline mirror::Object* MarkCompact::GetMarkedForwardAddress(mirror::Object* obj) const {
......
if (objects_before_forwarding_->HasAddress(obj)) {
......
mirror::Object* ret =
reinterpret_cast<mirror::Object*>(obj->GetLockWord(false).ForwardingAddress());
......
return ret;
}
......
return obj;
}
~~~
這個函數定義在文件art/runtime/gc/collector/mark_compact.cc中。
如果對象obj位于MarkCompact類的成員變量objects_before_forwarding_描述的一個ContinuousSpaceBitmap中,那么就說明它是一個位于當前正在處理的Bump Pointer Space的對象。又由于對象obj是一個根集對象,也就是它肯定是活著的,因此就可以從它的LockWord中獲取到它的Forwarding Address,也就是它移動后的地址。這個地址是在前面分析的MarkCompact類的成員函數ForwardObject計算并且設置的。
回到MarkCompact類的成員函數UpdateReferences中,更新完成根集對象對正在處理的Bump Pointer Space的引用之后,接下來繼續更新Image Space、Zygote Space和Non Moving Space對正在處理的Bump Pointer Space的引用。這三個Space均是保存在ART運行時堆的Continuous Space列表中。同時,保存在這個Continuous Space列表中的Space還包含當前正在處理的Bump Pointer Space,但是由于這個Bump Pointer Space既沒有關聯有Mod Union Table,也沒有關聯有Live Bitmap,因此,中間的for循環只是用來更新Image Space、Zygote Space和Non Moving Space對正在處理的Bump Pointer Space的引用。
對于Image Space和Zygote Space,它們都關聯有Mod Union Table,因此,我們就可以通過調用這個Mod Union Table的成員函數UpdateAndMarkReferences來遍歷上次GC以來發生過修改的對象。并且對于每一個這樣的對象,都調用MarkCompact類的靜態成員函數UpdateHeapReferenceCallback更新它們對當前正在處理的Bump Pointer Space的引用。
MarkCompact類的靜態成員函數UpdateHeapReferenceCallback實現如下所示:
~~~
void MarkCompact::UpdateHeapReferenceCallback(mirror::HeapReference<mirror::Object>* reference,
void* arg) {
reinterpret_cast<MarkCompact*>(arg)->UpdateHeapReference(reference);
}
~~~
這個函數定義在文件art/runtime/gc/collector/mark_compact.cc中。
MarkCompact類的靜態成員函數UpdateHeapReferenceCallback通過調用另外一個成員函數UpdateHeapReference來更新參數reference描述的位置(位于Image Space和Zygote Space上的某個對象的某個成員變量)對當前正在處理的Bump Pointer Space的引用,如下所示:
~~~
inline void MarkCompact::UpdateHeapReference(mirror::HeapReference<mirror::Object>* reference) {
mirror::Object* obj = reference->AsMirrorPtr();
if (obj != nullptr) {
mirror::Object* new_obj = GetMarkedForwardAddress(obj);
if (obj != new_obj) {
DCHECK(new_obj != nullptr);
reference->Assign(new_obj);
}
}
}
~~~
這個函數定義在文件art/runtime/gc/collector/mark_compact.cc中。
MarkCompact類的成員函數UpdateHeapReference與前面分析的MarkCompact類的成員函數UpdateRootCallback的實現邏輯基本上是一樣的,都是先通過調用MarkCompact類的成員函數GetMarkedForwardAddress判斷參數reference描述的位置引用的對象是否設置有Forwarding Address。如果設置有的話,就需要修改該位置的值。
回到MarkCompact類的成員函數UpdateReferences中,對于Non Moving Space,它沒有關聯有Mod Union Table,但是它關聯有Live Bitmap。因此,通過這個Live Bitmap,也可以逐個地檢查當前Non Moving Space的存活對象是否引用了當前正在處理的Bump Pointer Space的對象。如果有引用,那么就通過UpdateObjectReferencesVisitor類的操作符重載函數()對它們的引用位置進行修改。
UpdateObjectReferencesVisitor類的操作符重載函數()的實現如下所示:
~~~
class UpdateObjectReferencesVisitor {
public:
explicit UpdateObjectReferencesVisitor(MarkCompact* collector) : collector_(collector) {
}
void operator()(mirror::Object* obj) const SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE {
collector_->UpdateObjectReferences(obj);
}
private:
MarkCompact* const collector_;
};
~~~
這個函數定義在文件art/runtime/gc/collector/mark_compact.cc中。
從這里就可以看到,在Non Moving Space上分配的對象,是通過調用MarkCompact類的成員函數UpdateObjectReferences來修改它們對當前正在處理的Bump Pointer Space的引用的。
MarkCompact類的成員函數UpdateObjectReferences的實現如下所示:
~~~
void MarkCompact::UpdateObjectReferences(mirror::Object* obj) {
UpdateReferenceVisitor visitor(this);
obj->VisitReferences<kMovingClasses>(visitor, visitor);
}
~~~
這個函數定義在文件art/runtime/gc/collector/mark_compact.cc中。
MarkCompact類的成員函數UpdateObjectReferences通過調用Object類的成員函數VisitReferences來遍歷對象obj每一個類型為引用的成員變量,并且通過UpdateReferenceVisitor類的操作符重載函數()來更新它們對當前正在處理的Bump Pointer Space的引用。
UpdateReferenceVisitor類的操作符重載函數()有兩個版本的實現,如下所示:
~~~
class UpdateReferenceVisitor {
public:
explicit UpdateReferenceVisitor(MarkCompact* collector) : collector_(collector) {
}
void operator()(Object* obj, MemberOffset offset, bool /*is_static*/) const
ALWAYS_INLINE EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::heap_bitmap_lock_) {
collector_->UpdateHeapReference(obj->GetFieldObjectReferenceAddr<kVerifyNone>(offset));
}
void operator()(mirror::Class* /*klass*/, mirror::Reference* ref) const
EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::heap_bitmap_lock_) {
collector_->UpdateHeapReference(
ref->GetFieldObjectReferenceAddr<kVerifyNone>(mirror::Reference::ReferentOffset()));
}
private:
MarkCompact* const collector_;
};
~~~
這兩個函數定義在文件art/runtime/gc/collector/mark_compact.cc中。
如果對象obj有一個引用類型的成員變量,那么這個成員變量要么是一個普通的引用,即是一個強引用,要么是一個弱引用,即Soft Reference、Weak Reference、Phantom Rerference或者Finalizer Reference。對于前者,通過上面版本的操作符重載函數()進行處理;而對于后者,通過下面版本的操作符重載函數()進行處理。這兩者唯一的區別就是獲得被引用對象的方式不同。一旦獲得了被引用對象,就可以調用前面分析過的MarkCompact類的成員函數UpdateHeapReference來更新對應的成員變量的值了。
回到MarkCompact類的成員函數UpdateReferences中,這時候Image Space、Zygote Space和Non Moving Space的對象對當前正在處理的Bump Pointer Space的對象的引用就更新完畢,接下來需要繼續對Large Object Space和Bump Pointer Space進行同樣的處理。
首先看對Large Object Space的處理。從前面[ART運行時Compacting GC為新創建對象分配內存的過程分析](http://blog.csdn.net/luoshengyang/article/details/44910271)一文可以知道,在Large Object Space上分配的對象都是屬于原子類數組對象。原子類數組對象只有一個引用類型的成員變量,它引用的是一個Class對象,該Class對象描述原子類數組對象的類型。除此之外,原子類數組對象就沒有其它引用類型的成員變量了。
ART運行時定義了一個常量kMovingClasses,當ART運行時支持Mark-Compact GC時,它的值就等于false,如下所示:
~~~
// True if we allow moving classes.
static constexpr bool kMovingClasses = !kMarkCompactSupport;
~~~
這個常量定義在文件art/runtime/globals.h中。
又當常量kMovingClasses的值等于false時,ART運行時在分配Class對象時,都會在Non Moving Space進行分配,如下所示:
~~~
mirror::Class* ClassLinker::AllocClass(Thread* self, mirror::Class* java_lang_Class,
uint32_t class_size) {
......
gc::Heap* heap = Runtime::Current()->GetHeap();
mirror::Class::InitializeClassVisitor visitor(class_size);
mirror::Object* k = kMovingClasses ?
heap->AllocObject<true>(self, java_lang_Class, class_size, visitor) :
heap->AllocNonMovableObject<true>(self, java_lang_Class, class_size, visitor);
......
return k->AsClass();
}
~~~
這個函數定義在文件art/runtime/class_linker.cc。
這意味著在Large Object Space上分配的對象,不可能會引用在Bump Pointer Space分配的對象,因此MarkCompact類的成員函數UpdateReferences就不需要對Large Object Space作任何的處理。
我們再來看MarkCompact類的成員函數UpdateReferences對Bump Pointer Space的處理。這個Bump Pointer Space實際上就是正在處理的Bump Pointer Space,在上面分配的對象是可能發生相互引用的情況的,因此MarkCompact類的成員函數UpdateReferences就需要對它進行處理。
雖然Bump Pointer Space既沒有關聯有Mod Union Table,也沒有關聯有Live Bitmap,不過MarkCompact類的成員變量objects_before_forwarding_描述的ContinuousSpaceBitmap起到的作用與Live Bitmap是一樣的,因此MarkCompact類的成員函數UpdateReferences就可以像處理Non Moving Space的方式一樣處理Bump Pointer Space。
現在,就剩下ART運行時內部分配的對象以及那些特殊處理的引用對象沒有處理了。ART運行時內部分配的對象指的就是那些常量字符串池的字符串對象、Monitor對象和在JNI創建的全局弱引用對象等。對于這一類存活的對象,通過調用Runtime類的成員函數SweepSystemWeaks進行遍歷。Runtime類的成員函數SweepSystemWeaks在遍歷這些對象的過程中,會調用MarkCompact類的靜態成員函數MarkedForwardingAddressCallback來判斷它們是否引用了當前正在處理的Bump Pointer Space的對象。如果引用了的話,那么就會更新相應的位置的引用值。
MarkCompact類的靜態成員函數MarkedForwardingAddressCallback的實現如下所示:
~~~
mirror::Object* MarkCompact::MarkedForwardingAddressCallback(mirror::Object* obj, void* arg) {
return reinterpret_cast<MarkCompact*>(arg)->GetMarkedForwardAddress(obj);
}
~~~
這個函數定義在文件art/runtime/gc/collector/mark_compact.cc中。
從這里就可以看到,MarkCompact類的靜態成員函數MarkedForwardingAddressCallback是調用前面分析過的MarkCompact類的成員函數GetMarkedForwardAddress來決斷對象obj是否設置有Forwarding Address的。如果設置有Forwarding Address,那么就說明對象obj是位于當前正在處理的Bump Pointer Space中的,因此就會把該Forwarding Address返回給調用者,以便調用者更新對應位置的引用值。
最后,就剩下引用對象沒有處理沒有處理了。引用對象,即Soft Reference、Weak Reference、Phantom Rerference和Finalizer Reference這些類型的對象,它們都是通過ReferenceProcessor類來進行處理的。ReferenceProcessor類內部維護有了一個目標對象已經被回收了的引用對象列表。這些引用對象有可能是在當前正在處理的Bump Pointer Space中分配的,因此就需要對該列表進行更新。這是通過調用ReferenceProcessor類的成員函數UpdateRoots進行處理的,并且也是通過MarkCompact類的靜態成員函數MarkedForwardingAddressCallback來獲得是在當前正在處理的Bump Pointer Space中分配的對象的Forwarding Address的。
這樣,當MarkCompact類的成員函數UpdateReferences執行完畢,所有引用了位于當前正在處理的Bump Pointer Space上的對象的位置均已得到了更新。回到MarkCompact類的成員函數Compact中,它接下來要做的一件事情就是調用另外一個成員函數MoveObjects對當前正在處理的Bump Pointer Space的對象進行移動,也就是將存活的對象按地址值從小到大的順序依次排列在Bump Pointer Space的前半部分,以便解決內存碎片問題。
MarkCompact類的成員函數MoveObjects的實現如下所示:
~~~
void MarkCompact::MoveObjects() {
TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
// Move the objects in the before forwarding bitmap.
MoveObjectVisitor visitor(this);
objects_before_forwarding_->VisitMarkedRange(reinterpret_cast<uintptr_t>(space_->Begin()),
reinterpret_cast<uintptr_t>(space_->End()),
visitor);
CHECK(lock_words_to_restore_.empty());
}
~~~
這個函數定義在文件art/runtime/gc/collector/mark_compact.cc中。
由于前面已經將當前正在處理的Bump Pointer Space上每一個存活對象的新地址都已經計算好了,因此現在只需要將它們從原地址拷貝過去即可。其中,當前正在處理的Bump Pointer Space上的存活對象可以通過MarkCompact類的成員變量objects_before_forwarding_指向的一個ContinuousSpaceBitmap對象獲得,而這些存活對象的移動是通過MoveObjectVisitor類的操作符重載函數()來實現的,如下所示:
~~~
class MoveObjectVisitor {
public:
explicit MoveObjectVisitor(MarkCompact* collector) : collector_(collector) {
}
void operator()(mirror::Object* obj) const SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE {
collector_->MoveObject(obj, obj->SizeOf());
}
private:
MarkCompact* const collector_;
};
~~~
這個函數定義在文件art/runtime/gc/collector/mark_compact.cc中。
從這里可以看到,MoveObjectVisitor類的操作符重載函數()是通過調用MarkCompact類的成員函數MoveObject來移動參數obj描述的對象的,后者的實現如下所示:
~~~
void MarkCompact::MoveObject(mirror::Object* obj, size_t len) {
// Look at the forwarding address stored in the lock word to know where to copy.
DCHECK(space_->HasAddress(obj)) << obj;
uintptr_t dest_addr = obj->GetLockWord(false).ForwardingAddress();
mirror::Object* dest_obj = reinterpret_cast<mirror::Object*>(dest_addr);
DCHECK(space_->HasAddress(dest_obj)) << dest_obj;
// Use memmove since there may be overlap.
memmove(reinterpret_cast<void*>(dest_addr), reinterpret_cast<const void*>(obj), len);
// Restore the saved lock word if needed.
LockWord lock_word;
if (UNLIKELY(objects_with_lockword_->Test(obj))) {
lock_word = lock_words_to_restore_.front();
lock_words_to_restore_.pop_front();
}
dest_obj->SetLockWord(lock_word, false);
}
~~~
這個函數定義在文件art/runtime/gc/collector/mark_compact.cc中。
這里首先需要明確,參數obj是位于正在處理的Bump Pointer Space的,因此,我們就可以通過它的LockWord獲得它的Forwarding Address,也就是它要移動至的新地址。有了這個新地址之后,就可以通過memmove將它的內容從舊地址拷貝到新地址了。
由于對象obj的LockWord被借用了來保存新地址,因此,當它被移動至新地址之后,需要恢復它原先的LockWord值。當然,并不是所有要移動的對象的LockWord值都需要恢復,因為有些對象的LockWord值本來就是空的。對于原來的LockWord值為空的對象,只需要將移動后得到的對象的LockWord值也設置為空即可。而對于原來的LockWord值不空的對象,可以通過MarkCompact類的成員變量lock_words_to_restore_指向的一個隊列獲得。并且判斷對象obj原來的LockWord值不為空可以通過MarkCompact類的成員變量objects_with_lockword_指向的一個ContinuousSpaceBitmap對象判斷。
最后一點還需要注意的是,在計算正在處理的Bump Pointer Space上的存活對象的新對象時,是按照地址值從小到大的順序進行的。也就是說,對于原來LockWord值不為空的對象,它們原來的LockWord值也是按照對象地址從小到大的順序保存在MarkCompact類的成員變量lock_words_to_restore_指向的一個隊列中的。現在執行移動對象的操作時,也是按照對象地址從小到大的順序進行的,因此就可以依次從上述隊列中準確地獲得對象原先的LockWord值。
這樣,Mark-Compact GC的回收階段也執行完成了,最后剩下的結束階段是通過調用MarkCompact類的成員函數FinishPhase實現的,如下所示:
~~~
void MarkCompact::FinishPhase() {
TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
space_ = nullptr;
CHECK(mark_stack_->IsEmpty());
mark_stack_->Reset();
// Clear all of the spaces' mark bitmaps.
WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
heap_->ClearMarkedObjects();
// Release our bitmaps.
objects_before_forwarding_.reset(nullptr);
objects_with_lockword_.reset(nullptr);
}
~~~
這個函數定義在文件art/runtime/gc/collector/mark_compact.cc中。
Mark-Comapctt GC的結束階段主要是執行一些清理工作,包括:
1. 將MarkCompact類的成員變量space_置空。這個成員變量用來指定當前要進壓縮處理的Bump Pointer Space。每次在執行Mark-Compact GC之前,會首先對它進行初始化。
2. 重置ART運行時堆的Mark Stack。這個Mark Stack保存在MarkCompact類的成員變量mark_stack_。在每次Mark-Compact GC的初始化階段,都會對該成員變量進行初始化。
3. 調用Heap類的成員函數ClearMarkedObjects對ART運行時堆的各個Space的Mark Bitmap進行清零的操作,以便下次可以使用。
4. 將MarkCompact類的成員變量objects_before_forwarding_和objects_with_lockword_置空。它們在每次Mark-Compact GC的標記階段會被重新創建和初始化,并且在回收階段進行使用。
至此,Mark-Compact GC的執行過程就分析完成了。與前面[ART運行時Semi-Space(SS)和Generational Semi-Space(GSS)GC執行過程分析](http://blog.csdn.net/luoshengyang/article/details/45017207)一文分析的Semi-Space GC和Generational Semi-Space GC相比,它們的共同特點都是在Stop-the-word前提下進行的,并且都是通過移動對象來實現垃圾回收和內存壓縮的目的。不過前者的對象移動操作是就地進行的,而后兩者的對象移動操作是要通過一個額外的Space來進行的。當然,Mark-Compact GC的對象移動操作可以就地進行并不是免費的午餐,它要付出的代價在回收階段執行一個額外的新地址計算操作。這又是一個計算機世界以時間換空間或者說以空間換時間的例子。
現在,我們就對ART運行時的Mark-Sweep GC和Compacting GC都做了分析,也知道了它們的優缺點。如果我們能夠揚長避短,那么就可以既解決GC的效率問題,又能解決內存的碎片問題。在接下來的一篇文章中,我們就會重點分析ART運行時是如何最大限度地發揮Mark-Sweep GC和Compacting GC的長處的
- 前言
- Android組件設計思想
- Android源代碼開發和調試環境搭建
- Android源代碼下載和編譯
- Android源代碼情景分析法
- Android源代碼調試分析法
- 手把手教你為手機編譯ROM
- 在Ubuntu上下載、編譯和安裝Android最新源代碼
- 在Ubuntu上下載、編譯和安裝Android最新內核源代碼(Linux Kernel)
- 如何單獨編譯Android源代碼中的模塊
- 在Ubuntu上為Android系統編寫Linux內核驅動程序
- 在Ubuntu上為Android系統內置C可執行程序測試Linux內核驅動程序
- 在Ubuntu上為Android增加硬件抽象層(HAL)模塊訪問Linux內核驅動程序
- 在Ubuntu為Android硬件抽象層(HAL)模塊編寫JNI方法提供Java訪問硬件服務接口
- 在Ubuntu上為Android系統的Application Frameworks層增加硬件訪問服務
- 在Ubuntu上為Android系統內置Java應用程序測試Application Frameworks層的硬件服務
- Android源代碼倉庫及其管理工具Repo分析
- Android編譯系統簡要介紹和學習計劃
- Android編譯系統環境初始化過程分析
- Android源代碼編譯命令m/mm/mmm/make分析
- Android系統鏡像文件的打包過程分析
- 從CM刷機過程和原理分析Android系統結構
- Android系統架構概述
- Android系統整體架構
- android專用驅動
- Android硬件抽象層HAL
- Android應用程序組件
- Android應用程序框架
- Android用戶界面架構
- Android虛擬機之Dalvik虛擬機
- Android硬件抽象層
- Android硬件抽象層(HAL)概要介紹和學習計劃
- Android專用驅動
- Android Logger驅動系統
- Android日志系統驅動程序Logger源代碼分析
- Android應用程序框架層和系統運行庫層日志系統源代碼分析
- Android日志系統Logcat源代碼簡要分析
- Android Binder驅動系統
- Android進程間通信(IPC)機制Binder簡要介紹和學習計劃
- 淺談Service Manager成為Android進程間通信(IPC)機制Binder守護進程之路
- 淺談Android系統進程間通信(IPC)機制Binder中的Server和Client獲得Service Manager接口之路
- Android系統進程間通信(IPC)機制Binder中的Server啟動過程源代碼分析
- Android系統進程間通信(IPC)機制Binder中的Client獲得Server遠程接口過程源代碼分析
- Android系統進程間通信Binder機制在應用程序框架層的Java接口源代碼分析
- Android Ashmem驅動系統
- Android系統匿名共享內存Ashmem(Anonymous Shared Memory)簡要介紹和學習計劃
- Android系統匿名共享內存Ashmem(Anonymous Shared Memory)驅動程序源代碼分析
- Android系統匿名共享內存Ashmem(Anonymous Shared Memory)在進程間共享的原理分析
- Android系統匿名共享內存(Anonymous Shared Memory)C++調用接口分析
- Android應用程序進程管理
- Android應用程序進程啟動過程的源代碼分析
- Android系統進程Zygote啟動過程的源代碼分析
- Android系統默認Home應用程序(Launcher)的啟動過程源代碼分析
- Android應用程序消息機制
- Android應用程序消息處理機制(Looper、Handler)分析
- Android應用程序線程消息循環模型分析
- Android應用程序輸入事件分發和處理機制
- Android應用程序鍵盤(Keyboard)消息處理機制分析
- Android應用程序UI架構
- Android系統的開機畫面顯示過程分析
- Android幀緩沖區(Frame Buffer)硬件抽象層(HAL)模塊Gralloc的實現原理分析
- SurfaceFlinger
- Android系統Surface機制的SurfaceFlinger服務
- SurfaceFlinger服務簡要介紹和學習計劃
- 啟動過程分析
- 對幀緩沖區(Frame Buffer)的管理分析
- 線程模型分析
- 渲染應用程序UI的過程分析
- Android應用程序與SurfaceFlinger服務的關系
- 概述和學習計劃
- 連接過程分析
- 共享UI元數據(SharedClient)的創建過程分析
- 創建Surface的過程分析
- 渲染Surface的過程分析
- Android應用程序窗口(Activity)
- 實現框架簡要介紹和學習計劃
- 運行上下文環境(Context)的創建過程分析
- 窗口對象(Window)的創建過程分析
- 視圖對象(View)的創建過程分析
- 與WindowManagerService服務的連接過程分析
- 繪圖表面(Surface)的創建過程分析
- 測量(Measure)、布局(Layout)和繪制(Draw)過程分析
- WindowManagerService
- WindowManagerService的簡要介紹和學習計劃
- 計算Activity窗口大小的過程分析
- 對窗口的組織方式分析
- 對輸入法窗口(Input Method Window)的管理分析
- 對壁紙窗口(Wallpaper Window)的管理分析
- 計算窗口Z軸位置的過程分析
- 顯示Activity組件的啟動窗口(Starting Window)的過程分析
- 切換Activity窗口(App Transition)的過程分析
- 顯示窗口動畫的原理分析
- Android控件TextView的實現原理分析
- Android視圖SurfaceView的實現原理分析
- Android應用程序UI硬件加速渲染
- 簡要介紹和學習計劃
- 環境初始化過程分析
- 預加載資源地圖集服務(Asset Atlas Service)分析
- Display List構建過程分析
- Display List渲染過程分析
- 動畫執行過程分析
- Android應用程序資源管理框架
- Android資源管理框架(Asset Manager)
- Asset Manager 簡要介紹和學習計劃
- 編譯和打包過程分析
- Asset Manager的創建過程分析
- 查找過程分析
- Dalvik虛擬機和ART虛擬機
- Dalvik虛擬機
- Dalvik虛擬機簡要介紹和學習計劃
- Dalvik虛擬機的啟動過程分析
- Dalvik虛擬機的運行過程分析
- Dalvik虛擬機JNI方法的注冊過程分析
- Dalvik虛擬機進程和線程的創建過程分析
- Dalvik虛擬機垃圾收集機制簡要介紹和學習計劃
- Dalvik虛擬機Java堆創建過程分析
- Dalvik虛擬機為新創建對象分配內存的過程分析
- Dalvik虛擬機垃圾收集(GC)過程分析
- ART虛擬機
- Android ART運行時無縫替換Dalvik虛擬機的過程分析
- Android運行時ART簡要介紹和學習計劃
- Android運行時ART加載OAT文件的過程分析
- Android運行時ART加載類和方法的過程分析
- Android運行時ART執行類方法的過程分析
- ART運行時垃圾收集機制簡要介紹和學習計劃
- ART運行時Java堆創建過程分析
- ART運行時為新創建對象分配內存的過程分析
- ART運行時垃圾收集(GC)過程分析
- ART運行時Compacting GC簡要介紹和學習計劃
- ART運行時Compacting GC堆創建過程分析
- ART運行時Compacting GC為新創建對象分配內存的過程分析
- ART運行時Semi-Space(SS)和Generational Semi-Space(GSS)GC執行過程分析
- ART運行時Mark-Compact( MC)GC執行過程分析
- ART運行時Foreground GC和Background GC切換過程分析
- Android安全機制
- SEAndroid安全機制簡要介紹和學習計劃
- SEAndroid安全機制框架分析
- SEAndroid安全機制中的文件安全上下文關聯分析
- SEAndroid安全機制中的進程安全上下文關聯分析
- SEAndroid安全機制對Android屬性訪問的保護分析
- SEAndroid安全機制對Binder IPC的保護分析
- 從NDK在非Root手機上的調試原理探討Android的安全機制
- APK防反編譯
- Android視頻硬解穩定性問題探討和處理
- Android系統的智能指針(輕量級指針、強指針和弱指針)的實現原理分析
- Android應用程序安裝過程源代碼分析
- Android應用程序啟動過程源代碼分析
- 四大組件源代碼分析
- Activity
- Android應用程序的Activity啟動過程簡要介紹和學習計劃
- Android應用程序內部啟動Activity過程(startActivity)的源代碼分析
- 解開Android應用程序組件Activity的"singleTask"之謎
- Android應用程序在新的進程中啟動新的Activity的方法和過程分析
- Service
- Android應用程序綁定服務(bindService)的過程源代碼分析
- ContentProvider
- Android應用程序組件Content Provider簡要介紹和學習計劃
- Android應用程序組件Content Provider應用實例
- Android應用程序組件Content Provider的啟動過程源代碼分析
- Android應用程序組件Content Provider在應用程序之間共享數據的原理分析
- Android應用程序組件Content Provider的共享數據更新通知機制分析
- BroadcastReceiver
- Android系統中的廣播(Broadcast)機制簡要介紹和學習計劃
- Android應用程序注冊廣播接收器(registerReceiver)的過程分析
- Android應用程序發送廣播(sendBroadcast)的過程分析