From df386c551405ce9668e827584f744c6f098761fa Mon Sep 17 00:00:00 2001 From: Hiroshi Yamauchi Date: Tue, 8 Apr 2014 16:21:52 -0700 Subject: [PATCH] GSS: Fix the bump pointer space only collection. Fixes b/13912464 where the clear soft reference behavior accidentally disabled the bump pointer space only collection. Changed the collector name so that the GC logs would indicate the generational mode and the collection mode. Peformance enhancement: instead of triggering the whole heap collection every 5 collections, count the bytes promoted since the last whole heap collection and use it to decide when to trigger the whole heap collection. This improves MemAllocTest by 5-10% (N4 and host). Bug: 13912464 Bug: 11650816 Bug: 9986565 Change-Id: I653a0dca62a8b54adf69abe2940a41eac70f809b --- runtime/gc/collector/mark_sweep.cc | 5 +++- runtime/gc/collector/semi_space.cc | 59 +++++++++++++++++++++++++++++++------- runtime/gc/collector/semi_space.h | 8 ++++++ runtime/gc/heap.cc | 6 ++-- 4 files changed, 62 insertions(+), 16 deletions(-) diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc index 944ef8d88..bb41b574e 100644 --- a/runtime/gc/collector/mark_sweep.cc +++ b/runtime/gc/collector/mark_sweep.cc @@ -129,7 +129,10 @@ void MarkSweep::InitializePhase() { ReaderMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_); mark_bitmap_ = heap_->GetMarkBitmap(); } - + if (!clear_soft_references_) { + // Always clear soft references if a non-sticky collection. + clear_soft_references_ = GetGcType() != collector::kGcTypeSticky; + } // Do any pre GC verification. timings_.NewSplit("PreGcVerification"); heap_->PreGcVerification(this); diff --git a/runtime/gc/collector/semi_space.cc b/runtime/gc/collector/semi_space.cc index 1366858fe..e82d533b1 100644 --- a/runtime/gc/collector/semi_space.cc +++ b/runtime/gc/collector/semi_space.cc @@ -65,6 +65,8 @@ namespace collector { static constexpr bool kProtectFromSpace = true; static constexpr bool kClearFromSpace = true; static constexpr bool kStoreStackTraces = false; +static constexpr bool kUseBytesPromoted = true; +static constexpr size_t kBytesPromotedThreshold = 4 * MB; void SemiSpace::BindBitmaps() { timings_.StartSplit("BindBitmaps"); @@ -102,8 +104,10 @@ SemiSpace::SemiSpace(Heap* heap, bool generational, const std::string& name_pref generational_(generational), last_gc_to_space_end_(nullptr), bytes_promoted_(0), + bytes_promoted_since_last_whole_heap_collection_(0), whole_heap_collection_(true), - whole_heap_collection_interval_counter_(0) { + whole_heap_collection_interval_counter_(0), + collector_name_(name_) { } void SemiSpace::InitializePhase() { @@ -150,14 +154,31 @@ void SemiSpace::MarkingPhase() { // collection, collect the whole heap (and reset the interval // counter to be consistent.) whole_heap_collection_ = true; - whole_heap_collection_interval_counter_ = 0; + if (!kUseBytesPromoted) { + whole_heap_collection_interval_counter_ = 0; + } } if (whole_heap_collection_) { VLOG(heap) << "Whole heap collection"; + name_ = collector_name_ + " whole"; } else { VLOG(heap) << "Bump pointer space only collection"; + name_ = collector_name_ + " bps"; + } + } + + if (!clear_soft_references_) { + if (!generational_) { + // If non-generational, always clear soft references. + clear_soft_references_ = true; + } else { + // If generational, clear soft references if a whole heap collection. + if (whole_heap_collection_) { + clear_soft_references_ = true; + } } } + Locks::mutator_lock_->AssertExclusiveHeld(self_); TimingLogger::ScopedSplit split("MarkingPhase", &timings_); @@ -762,18 +783,34 @@ void SemiSpace::FinishPhase() { if (generational_) { // Decide whether to do a whole heap collection or a bump pointer // only space collection at the next collection by updating - // whole_heap_collection. Enable whole_heap_collection once every - // kDefaultWholeHeapCollectionInterval collections. + // whole_heap_collection. if (!whole_heap_collection_) { - --whole_heap_collection_interval_counter_; - DCHECK_GE(whole_heap_collection_interval_counter_, 0); - if (whole_heap_collection_interval_counter_ == 0) { - whole_heap_collection_ = true; + if (!kUseBytesPromoted) { + // Enable whole_heap_collection once every + // kDefaultWholeHeapCollectionInterval collections. + --whole_heap_collection_interval_counter_; + DCHECK_GE(whole_heap_collection_interval_counter_, 0); + if (whole_heap_collection_interval_counter_ == 0) { + whole_heap_collection_ = true; + } + } else { + // Enable whole_heap_collection if the bytes promoted since + // the last whole heap collection exceeds a threshold. + bytes_promoted_since_last_whole_heap_collection_ += bytes_promoted_; + if (bytes_promoted_since_last_whole_heap_collection_ >= kBytesPromotedThreshold) { + whole_heap_collection_ = true; + } } } else { - DCHECK_EQ(whole_heap_collection_interval_counter_, 0); - whole_heap_collection_interval_counter_ = kDefaultWholeHeapCollectionInterval; - whole_heap_collection_ = false; + if (!kUseBytesPromoted) { + DCHECK_EQ(whole_heap_collection_interval_counter_, 0); + whole_heap_collection_interval_counter_ = kDefaultWholeHeapCollectionInterval; + whole_heap_collection_ = false; + } else { + // Reset it. + bytes_promoted_since_last_whole_heap_collection_ = bytes_promoted_; + whole_heap_collection_ = false; + } } } // Clear all of the spaces' mark bitmaps. diff --git a/runtime/gc/collector/semi_space.h b/runtime/gc/collector/semi_space.h index f067cb28e..34427517f 100644 --- a/runtime/gc/collector/semi_space.h +++ b/runtime/gc/collector/semi_space.h @@ -217,6 +217,11 @@ class SemiSpace : public GarbageCollector { // bump pointer space to the non-moving space. uint64_t bytes_promoted_; + // Used for the generational mode. Keeps track of how many bytes of + // objects have been copied so far from the bump pointer space to + // the non-moving space, since the last whole heap collection. + uint64_t bytes_promoted_since_last_whole_heap_collection_; + // Used for the generational mode. When true, collect the whole // heap. When false, collect only the bump pointer spaces. bool whole_heap_collection_; @@ -228,6 +233,9 @@ class SemiSpace : public GarbageCollector { // How many bytes we avoided dirtying. size_t saved_bytes_; + // The name of the collector. + std::string collector_name_; + // Used for the generational mode. The default interval of the whole // heap collection. If N, the whole heap collection occurs every N // collections. diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc index 915e54f9a..daf0fb359 100644 --- a/runtime/gc/heap.cc +++ b/runtime/gc/heap.cc @@ -326,7 +326,8 @@ Heap::Heap(size_t initial_size, size_t growth_limit, size_t min_free, size_t max if (kMovingCollector) { // TODO: Clean this up. bool generational = post_zygote_collector_type_ == kCollectorTypeGSS; - semi_space_collector_ = new collector::SemiSpace(this, generational); + semi_space_collector_ = new collector::SemiSpace(this, generational, + generational ? "generational" : ""); garbage_collectors_.push_back(semi_space_collector_); concurrent_copying_collector_ = new collector::ConcurrentCopying(this); @@ -1859,9 +1860,6 @@ collector::GcType Heap::CollectGarbageInternal(collector::GcType gc_type, GcCaus << "Could not find garbage collector with collector_type=" << static_cast(collector_type_) << " and gc_type=" << gc_type; ATRACE_BEGIN(StringPrintf("%s %s GC", PrettyCause(gc_cause), collector->GetName()).c_str()); - if (!clear_soft_references) { - clear_soft_references = gc_type != collector::kGcTypeSticky; // TODO: GSS? - } collector->Run(gc_cause, clear_soft_references || runtime->IsZygote()); total_objects_freed_ever_ += collector->GetFreedObjects(); total_bytes_freed_ever_ += collector->GetFreedBytes(); -- 2.11.0