From 962cd7adf3d9d2a1dedf0318056a29e9390f1c38 Mon Sep 17 00:00:00 2001 From: Mathieu Chartier Date: Tue, 16 Aug 2016 12:15:59 -0700 Subject: [PATCH] Always mark zygote large objects for CC Prevent needing to gray holders of zygote large objects. System wide zygote space PSS after boot: 12644 kB -> 5571 kB for CC. Also PSS reduction in zygote large objects themselves since their gray bit would have been set each GC. Overall LOS savings hard to measure, could be up to 316 * 4KB per app since there are 316 zygote large objects. Also clear mod-union tables for image spaces to prevent dirty image pages if any of the image spaces point to zygote large objects. System wide .art mmap: 37432 kB -> 34372 kB System server before (N6P): LOS shared dirty: 12888 kB Zygote space shared dirty: 700 kB Zygote space private dirty: 868 kB .art private dirty: 1696 kB After: LOS shared dirty 13672 kB Zygote space shared dirty: 1072 kB Zygote space private dirty: 496 kB .art private dirty: 1432 kB Bug: 29516968 Test: test-art-host with baker CC, debug N6P phone booting Change-Id: Ia37ce2c11217cf56885bd1d1dc084332fcbb7843 --- runtime/gc/accounting/mod_union_table.cc | 9 +++++++ runtime/gc/accounting/mod_union_table.h | 8 ++++++- runtime/gc/collector/concurrent_copying.cc | 38 ++++++++++++++++++++++++++---- runtime/gc/collector/concurrent_copying.h | 2 ++ runtime/gc/heap.cc | 26 +++++++++++++------- 5 files changed, 70 insertions(+), 13 deletions(-) diff --git a/runtime/gc/accounting/mod_union_table.cc b/runtime/gc/accounting/mod_union_table.cc index 4e83913ad..35bcb187a 100644 --- a/runtime/gc/accounting/mod_union_table.cc +++ b/runtime/gc/accounting/mod_union_table.cc @@ -175,6 +175,11 @@ void ModUnionTableReferenceCache::ClearCards() { card_table->ModifyCardsAtomic(space_->Begin(), space_->End(), AgeCardVisitor(), visitor); } +void ModUnionTableReferenceCache::ClearTable() { + cleared_cards_.clear(); + references_.clear(); +} + class AddToReferenceArrayVisitor { public: AddToReferenceArrayVisitor(ModUnionTableReferenceCache* mod_union_table, @@ -526,6 +531,10 @@ void ModUnionTableCardCache::ClearCards() { card_table->ModifyCardsAtomic(space_->Begin(), space_->End(), AgeCardVisitor(), visitor); } +void ModUnionTableCardCache::ClearTable() { + card_bitmap_->Bitmap::Clear(); +} + // Mark all references to the alloc space(s). void ModUnionTableCardCache::UpdateAndMarkReferences(MarkObjectVisitor* visitor) { // TODO: Needs better support for multi-images? b/26317072 diff --git a/runtime/gc/accounting/mod_union_table.h b/runtime/gc/accounting/mod_union_table.h index bf665c50d..6aa2417f6 100644 --- a/runtime/gc/accounting/mod_union_table.h +++ b/runtime/gc/accounting/mod_union_table.h @@ -63,6 +63,9 @@ class ModUnionTable { // Set all the cards. virtual void SetCards() = 0; + // Clear all of the table. + virtual void ClearTable() = 0; + // Update the mod-union table using data stored by ClearCards. There may be multiple ClearCards // before a call to update, for example, back-to-back sticky GCs. Also mark references to other // spaces which are stored in the mod-union table. @@ -140,6 +143,8 @@ class ModUnionTableReferenceCache : public ModUnionTable { virtual void SetCards() OVERRIDE; + virtual void ClearTable() OVERRIDE; + protected: // Cleared card array, used to update the mod-union table. ModUnionTable::CardSet cleared_cards_; @@ -177,9 +182,10 @@ class ModUnionTableCardCache : public ModUnionTable { virtual bool ContainsCardFor(uintptr_t addr) OVERRIDE; - // Sets all the cards in the mod union table to be marked. virtual void SetCards() OVERRIDE; + virtual void ClearTable() OVERRIDE; + protected: // Cleared card bitmap, used to update the mod-union table. std::unique_ptr card_bitmap_; diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc index 071537db9..70faf4baf 100644 --- a/runtime/gc/collector/concurrent_copying.cc +++ b/runtime/gc/collector/concurrent_copying.cc @@ -228,6 +228,8 @@ void ConcurrentCopying::InitializePhase() { } LOG(INFO) << "GC end of InitializePhase"; } + // Mark all of the zygote large objects without graying them. + MarkZygoteLargeObjects(); } // Used to switch the thread roots of a thread from from-space refs to to-space refs. @@ -385,10 +387,18 @@ class ConcurrentCopying::VerifyGrayImmuneObjectsVisitor { void CheckReference(mirror::Object* ref, mirror::Object* holder, MemberOffset offset) const SHARED_REQUIRES(Locks::mutator_lock_) { if (ref != nullptr) { - CHECK(collector_->immune_spaces_.ContainsObject(ref)) - << "Non gray object references non immune object "<< ref << " " << PrettyTypeOf(ref) - << " in holder " << holder << " " << PrettyTypeOf(holder) << " offset=" - << offset.Uint32Value(); + if (!collector_->immune_spaces_.ContainsObject(ref)) { + // Not immune, must be a zygote large object. + CHECK(Runtime::Current()->GetHeap()->GetLargeObjectsSpace()->IsZygoteLargeObject( + Thread::Current(), ref)) + << "Non gray object references non immune, non zygote large object "<< ref << " " + << PrettyTypeOf(ref) << " in holder " << holder << " " << PrettyTypeOf(holder) + << " offset=" << offset.Uint32Value(); + } else { + // Make sure the large object class is immune since we will never scan the large object. + CHECK(collector_->immune_spaces_.ContainsObject( + ref->GetClass())); + } } } }; @@ -1440,6 +1450,26 @@ void ConcurrentCopying::Sweep(bool swap_bitmaps) { SweepLargeObjects(swap_bitmaps); } +void ConcurrentCopying::MarkZygoteLargeObjects() { + TimingLogger::ScopedTiming split(__FUNCTION__, GetTimings()); + Thread* const self = Thread::Current(); + WriterMutexLock rmu(self, *Locks::heap_bitmap_lock_); + space::LargeObjectSpace* const los = heap_->GetLargeObjectsSpace(); + // Pick the current live bitmap (mark bitmap if swapped). + accounting::LargeObjectBitmap* const live_bitmap = los->GetLiveBitmap(); + accounting::LargeObjectBitmap* const mark_bitmap = los->GetMarkBitmap(); + // Walk through all of the objects and explicitly mark the zygote ones so they don't get swept. + live_bitmap->VisitMarkedRange(reinterpret_cast(los->Begin()), + reinterpret_cast(los->End()), + [mark_bitmap, los, self](mirror::Object* obj) + REQUIRES(Locks::heap_bitmap_lock_) + SHARED_REQUIRES(Locks::mutator_lock_) { + if (los->IsZygoteLargeObject(self, obj)) { + mark_bitmap->Set(obj); + } + }); +} + void ConcurrentCopying::SweepLargeObjects(bool swap_bitmaps) { TimingLogger::ScopedTiming split("SweepLargeObjects", GetTimings()); RecordFreeLOS(heap_->GetLargeObjectsSpace()->Sweep(swap_bitmaps)); diff --git a/runtime/gc/collector/concurrent_copying.h b/runtime/gc/collector/concurrent_copying.h index a862802b2..55c457017 100644 --- a/runtime/gc/collector/concurrent_copying.h +++ b/runtime/gc/collector/concurrent_copying.h @@ -187,6 +187,8 @@ class ConcurrentCopying : public GarbageCollector { SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(Locks::heap_bitmap_lock_, !mark_stack_lock_); void SweepLargeObjects(bool swap_bitmaps) SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(Locks::heap_bitmap_lock_); + void MarkZygoteLargeObjects() + SHARED_REQUIRES(Locks::mutator_lock_); void FillWithDummyObject(mirror::Object* dummy_obj, size_t byte_size) REQUIRES(!mark_stack_lock_, !skipped_blocks_lock_, !immune_gray_stack_lock_) SHARED_REQUIRES(Locks::mutator_lock_); diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc index aa3bf61da..39f26e7fe 100644 --- a/runtime/gc/heap.cc +++ b/runtime/gc/heap.cc @@ -2556,15 +2556,25 @@ void Heap::PreZygoteFork() { // Create the zygote space mod union table. accounting::ModUnionTable* mod_union_table = - new accounting::ModUnionTableCardCache("zygote space mod-union table", this, - zygote_space_); + new accounting::ModUnionTableCardCache("zygote space mod-union table", this, zygote_space_); CHECK(mod_union_table != nullptr) << "Failed to create zygote space mod-union table"; - // Set all the cards in the mod-union table since we don't know which objects contain references - // to large objects. - mod_union_table->SetCards(); - // Filter out cards that do not to be dirty. This is mostly for CC collector so that it does - // not gray the objects on all the cards in the zygote space. - mod_union_table->FilterCards(); + + if (collector_type_ != kCollectorTypeCC) { + // Set all the cards in the mod-union table since we don't know which objects contain references + // to large objects. + mod_union_table->SetCards(); + } else { + // For CC we never collect zygote large objects. This means we do not need to set the cards for + // the zygote mod-union table and we can also clear all of the existing image mod-union tables. + // The existing mod-union tables are only for image spaces and may only reference zygote and + // image objects. + for (auto& pair : mod_union_tables_) { + CHECK(pair.first->IsImageSpace()); + CHECK(!pair.first->AsImageSpace()->GetImageHeader().IsAppImage()); + accounting::ModUnionTable* table = pair.second; + table->ClearTable(); + } + } AddModUnionTable(mod_union_table); large_object_space_->SetAllLargeObjectsAsZygoteObjects(self); if (collector::SemiSpace::kUseRememberedSet) { -- 2.11.0