The document summarizes the semi-space garbage collector used in ART. It discusses how the collector performs marking and reclaiming phases to compact objects within the bump pointer space. It also describes optimizations like the remembered set that avoid rescanning other spaces. The collector can perform whole heap collection if promotion or large object thresholds are exceeded.
2. Outline
• Current Garbage Collectors in ART
• Heap in VM Process
• Semi-Space Collector
• Optimization
• Whole Heap Collection
• Other Semi-Space Collector
– ZygoteCompactingCollector
3. Current Garbage Collectors in ART
• Mark-Sweep Collector
– Concurrent Sticky/Partial/Full (CMS)
– Non-Concurrent Sticky/Partial/Full (MS)
• Semi-Space Collector
– Generational Semi-Space
– Semi-Space(GSS+ Partial Mark-Sweep)
• Concurrent-Copying
– Under developing…
4. Heap in VM Process
Image Space
Zygote
Space
Main Space
Non Moving
Space
Temp_space
Bump pointer
Space
60+MB 10+MB 64MB
128MB 128MB
Large Object Space
5. Semi-Space Collector: Compacting
• It is for Bump pointer Space
• After one SS,
• So, it’s also named Compacting collector.
• For mark sweep, it is treated as normal space, like main space
7. Semi-Space Collector
• All phases in GC should suspend all mutators.
64 class SemiSpace : public GarbageCollector {
…
72 virtual bool IsConcurrent() const {
73 return false;
74 }
75 virtual void MarkingPhase() EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_);
76 virtual void ReclaimPhase() EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_);
77 virtual void FinishPhase() EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_);
…
}
8. Semi-Space Collector: Mark
• If object A is in from_space
– If two most significant bits of object A->monitor is
not 3
• Copy object A to to_space or promoted_space A’
• Update object A->monitor.
• Push New object A’ to mark_stack.
• Else if object is not in Immune_region
– Mark action same as mark_sweep action.
* |33|22222222221111|1111110000000000|
* |10|98765432109876|5432109876543210|
* |11| object’s new location address >>2 |
9. Semi-Space Collector: Reclaim
• Sweep
• BumpPointerSpace::Clear
– madvise(Begin(), Limit() - Begin(), MADV_DONTNEED)
madvise:: MADV_DONTNEED
Subsequent accesses of pages in this range will succeed, but will result either in
reloading of the memory contents from the underlying mapped file or zero-fill-
on-demand pages for mappings without an underlying file.
10. Optimization
• Though just collector garbage of bump pointer
space, the non moving space and main space
mast be scanned and marked. This is
inefficient.
• RememberedSet is involved by Hiroshi
Yamauchi. It is same to ModUnionTable. It
trace the reference from non-moving
space/main space to bump pointer space.
11. Process Cards
void Heap::ProcessCards(TimingLogger& timings, bool use_rem_sets) {
// Clear cards and keep track of cards cleared in the mod-union table.
for (const auto& space : continuous_spaces_) {
accounting::ModUnionTable* table = FindModUnionTableFromSpace(space);
+ accounting::RememberedSet* rem_set = FindRememberedSetFromSpace(space);
if (table != nullptr) {
const char* name = space->IsZygoteSpace() ? "ZygoteModUnionClearCards" :
"ImageModUnionClearCards";
TimingLogger::ScopedSplit split(name, &timings);
table->ClearCards();
+ } else if (use_rem_sets && rem_set != nullptr) {
+ DCHECK(collector::SemiSpace::kUseRememberedSet && collector_type_ == kCollectorTypeGSS)
+ << static_cast<int>(collector_type_);
+ TimingLogger::ScopedSplit split("AllocSpaceRemSetClearCards", &timings);
+ rem_set->ClearCards();
} else if (space->GetType() != space::kSpaceTypeBumpPointerSpace) {
TimingLogger::ScopedSplit split("AllocSpaceClearCards", &timings);
// No mod union table for the AllocSpace. Age the cards so that the GC knows that these cards
// were dirty before the GC started.
// TODO: Need to use atomic for the case where aged(cleaning thread) -> dirty(other thread)
// -> clean(cleaning thread).
// The races are we either end up with: Aged card, unaged card. Since we have the checkpoint
// roots and then we scan / update mod union tables after. We will always scan either card.
// If we end up with the non aged card, we scan it it in the pause.
card_table_->ModifyCardsAtomic(space->Begin(), space->End(), AgeCardVisitor(), VoidFunctor());
}
}
}
12. Update RememberedSet
void RememberedSet::UpdateAndMarkReferences(MarkObjectCallback* callback,
space::ContinuousSpace* target_space, void* arg) {
CardTable* card_table = heap_->GetCardTable();
bool contains_reference_to_target_space = false;
RememberedSetObjectVisitor obj_visitor(callback, target_space,
&contains_reference_to_target_space, arg);
SpaceBitmap* bitmap = space_->GetLiveBitmap();
CardSet remove_card_set;
for (byte* const card_addr : dirty_cards_) {
contains_reference_to_target_space = false;
uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card_addr));
DCHECK(space_->HasAddress(reinterpret_cast<mirror::Object*>(start)));
bitmap->VisitMarkedRange(start, start + CardTable::kCardSize, obj_visitor);
if (!contains_reference_to_target_space) {
// It was in the dirty card set, but it didn't actually contain
// a reference to the target space. So, remove it from the dirty
// card set so we won't have to scan it again (unless it gets
// dirty again.)
remove_card_set.insert(card_addr);
}
}
// Remove the cards that didn't contain a reference to the target
// space from the dirty card set.
for (byte* const card_addr : remove_card_set) {
DCHECK(dirty_cards_.find(card_addr) != dirty_cards_.end());
dirty_cards_.erase(card_addr);
}
}
13. GSS and Whole Heap Collection
• If promotion bytes or large object bytes
allocated exceeds threshold. GSS will do
partial Mark Sweep + Semi-Space collector on
whole heap.
14. ZygoteCompactingCollector
• When
– When Zygote fork the first process.
• How
1627 ZygoteCompactingCollector zygote_collector(this);
1628 zygote_collector.BuildBins(non_moving_space_);
1629 // Create a new bump pointer space which we will compact into.
1630 space::BumpPointerSpace target_space("zygote bump space",
non_moving_space_->End(), non_moving_space_->Limit());
1633 // Compact the bump pointer space to a new zygote bump pointer space.
1635 zygote_collector.SetFromSpace(bump_pointer_space_);
1636 zygote_collector.SetToSpace(&target_space);
1637 zygote_collector.Run(kGcCauseCollectorTransition, false);