diff options
author | Mathieu Chartier <mathieuc@google.com> | 2014-01-31 18:55:35 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2014-01-31 18:55:35 +0000 |
commit | 9aeeeac4ba0b136652f213d60a5a1990a333a629 (patch) | |
tree | 9ed565fec210c69dc136223edb882a9d858e0788 | |
parent | d65c39a050af53bef5f92221619b5416b1a8822e (diff) | |
parent | a1602f28c0e3127ad511712d4b08db89737ae901 (diff) | |
download | art-9aeeeac4ba0b136652f213d60a5a1990a333a629.zip art-9aeeeac4ba0b136652f213d60a5a1990a333a629.tar.gz art-9aeeeac4ba0b136652f213d60a5a1990a333a629.tar.bz2 |
Merge "Add zygote space as its own space type."
-rw-r--r-- | runtime/Android.mk | 1 | ||||
-rw-r--r-- | runtime/gc/accounting/space_bitmap.cc | 6 | ||||
-rw-r--r-- | runtime/gc/collector/mark_sweep.cc | 59 | ||||
-rw-r--r-- | runtime/gc/collector/mark_sweep.h | 16 | ||||
-rw-r--r-- | runtime/gc/collector/semi_space.cc | 58 | ||||
-rw-r--r-- | runtime/gc/collector/semi_space.h | 5 | ||||
-rw-r--r-- | runtime/gc/collector/sticky_mark_sweep.cc | 4 | ||||
-rw-r--r-- | runtime/gc/heap.cc | 53 | ||||
-rw-r--r-- | runtime/gc/heap.h | 3 | ||||
-rw-r--r-- | runtime/gc/space/dlmalloc_space.cc | 1 | ||||
-rw-r--r-- | runtime/gc/space/dlmalloc_space.h | 4 | ||||
-rw-r--r-- | runtime/gc/space/image_space.h | 8 | ||||
-rw-r--r-- | runtime/gc/space/malloc_space.cc | 138 | ||||
-rw-r--r-- | runtime/gc/space/malloc_space.h | 53 | ||||
-rw-r--r-- | runtime/gc/space/rosalloc_space.cc | 1 | ||||
-rw-r--r-- | runtime/gc/space/rosalloc_space.h | 4 | ||||
-rw-r--r-- | runtime/gc/space/space-inl.h | 2 | ||||
-rw-r--r-- | runtime/gc/space/space.cc | 56 | ||||
-rw-r--r-- | runtime/gc/space/space.h | 69 | ||||
-rw-r--r-- | runtime/gc/space/space_test.cc | 12 | ||||
-rw-r--r-- | runtime/gc/space/zygote_space.cc | 98 | ||||
-rw-r--r-- | runtime/gc/space/zygote_space.h | 95 |
22 files changed, 447 insertions, 299 deletions
diff --git a/runtime/Android.mk b/runtime/Android.mk index c180b17..bab250c 100644 --- a/runtime/Android.mk +++ b/runtime/Android.mk @@ -66,6 +66,7 @@ LIBART_COMMON_SRC_FILES := \ gc/space/malloc_space.cc \ gc/space/rosalloc_space.cc \ gc/space/space.cc \ + gc/space/zygote_space.cc \ hprof/hprof.cc \ image.cc \ indirect_reference_table.cc \ diff --git a/runtime/gc/accounting/space_bitmap.cc b/runtime/gc/accounting/space_bitmap.cc index 99800fc..b831843 100644 --- a/runtime/gc/accounting/space_bitmap.cc +++ b/runtime/gc/accounting/space_bitmap.cc @@ -128,9 +128,9 @@ void SpaceBitmap::Walk(SpaceBitmap::Callback* callback, void* arg) { // // The callback is not permitted to increase the max of either bitmap. void SpaceBitmap::SweepWalk(const SpaceBitmap& live_bitmap, - const SpaceBitmap& mark_bitmap, - uintptr_t sweep_begin, uintptr_t sweep_end, - SpaceBitmap::SweepCallback* callback, void* arg) { + const SpaceBitmap& mark_bitmap, + uintptr_t sweep_begin, uintptr_t sweep_end, + SpaceBitmap::SweepCallback* callback, void* arg) { CHECK(live_bitmap.bitmap_begin_ != NULL); CHECK(mark_bitmap.bitmap_begin_ != NULL); CHECK_EQ(live_bitmap.heap_begin_, mark_bitmap.heap_begin_); diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc index 5d450a7..862d06f 100644 --- a/runtime/gc/collector/mark_sweep.cc +++ b/runtime/gc/collector/mark_sweep.cc @@ -89,7 +89,8 @@ constexpr bool kCheckLocks = kDebugLocking; void MarkSweep::ImmuneSpace(space::ContinuousSpace* space) { // Bind live to mark bitmap if necessary. if (space->GetLiveBitmap() != space->GetMarkBitmap()) { - BindLiveToMarkBitmap(space); + CHECK(space->IsContinuousMemMapAllocSpace()); + space->AsContinuousMemMapAllocSpace()->BindLiveToMarkBitmap(); } // Add the space to the immune region. @@ -143,11 +144,6 @@ MarkSweep::MarkSweep(Heap* heap, bool is_concurrent, const std::string& name_pre mark_stack_(NULL), immune_begin_(NULL), immune_end_(NULL), - soft_reference_list_(NULL), - weak_reference_list_(NULL), - finalizer_reference_list_(NULL), - phantom_reference_list_(NULL), - cleared_reference_list_(NULL), live_stack_freeze_size_(0), gc_barrier_(new Barrier(0)), large_object_lock_("mark sweep large object lock", kMarkSweepLargeObjectLock), @@ -161,11 +157,6 @@ void MarkSweep::InitializePhase() { mark_stack_ = heap_->mark_stack_.get(); DCHECK(mark_stack_ != nullptr); SetImmuneRange(nullptr, nullptr); - soft_reference_list_ = nullptr; - weak_reference_list_ = nullptr; - finalizer_reference_list_ = nullptr; - phantom_reference_list_ = nullptr; - cleared_reference_list_ = nullptr; class_count_ = 0; array_count_ = 0; other_count_ = 0; @@ -347,7 +338,8 @@ void MarkSweep::ReclaimPhase() { timings_.EndSplit(); // Unbind the live and mark bitmaps. - UnBindBitmaps(); + TimingLogger::ScopedSplit split("UnBindBitmaps", &timings_); + GetHeap()->UnBindBitmaps(); } } @@ -589,14 +581,6 @@ void MarkSweep::MarkConcurrentRoots() { timings_.EndSplit(); } -void MarkSweep::BindLiveToMarkBitmap(space::ContinuousSpace* space) { - CHECK(space->IsMallocSpace()); - space::MallocSpace* alloc_space = space->AsMallocSpace(); - accounting::SpaceBitmap* live_bitmap = space->GetLiveBitmap(); - accounting::SpaceBitmap* mark_bitmap = alloc_space->BindLiveToMarkBitmap(); - GetHeap()->GetMarkBitmap()->ReplaceBitmap(mark_bitmap, live_bitmap); -} - class ScanObjectVisitor { public: explicit ScanObjectVisitor(MarkSweep* const mark_sweep) ALWAYS_INLINE @@ -893,14 +877,8 @@ class RecursiveMarkTask : public MarkStackTask<false> { // recursively marks until the mark stack is emptied. void MarkSweep::RecursiveMark() { TimingLogger::ScopedSplit split("RecursiveMark", &timings_); - // RecursiveMark will build the lists of known instances of the Reference classes. - // See DelayReferenceReferent for details. - CHECK(soft_reference_list_ == NULL); - CHECK(weak_reference_list_ == NULL); - CHECK(finalizer_reference_list_ == NULL); - CHECK(phantom_reference_list_ == NULL); - CHECK(cleared_reference_list_ == NULL); - + // RecursiveMark will build the lists of known instances of the Reference classes. See + // DelayReferenceReferent for details. if (kUseRecursiveMark) { const bool partial = GetGcType() == kGcTypePartial; ScanObjectVisitor scan_visitor(this); @@ -1146,13 +1124,13 @@ void MarkSweep::Sweep(bool swap_bitmaps) { DCHECK(mark_stack_->IsEmpty()); TimingLogger::ScopedSplit("Sweep", &timings_); for (const auto& space : GetHeap()->GetContinuousSpaces()) { - if (space->IsMallocSpace()) { - space::MallocSpace* malloc_space = space->AsMallocSpace(); + if (space->IsContinuousMemMapAllocSpace()) { + space::ContinuousMemMapAllocSpace* alloc_space = space->AsContinuousMemMapAllocSpace(); TimingLogger::ScopedSplit split( - malloc_space->IsZygoteSpace() ? "SweepZygoteSpace" : "SweepAllocSpace", &timings_); + alloc_space->IsZygoteSpace() ? "SweepZygoteSpace" : "SweepMallocSpace", &timings_); size_t freed_objects = 0; size_t freed_bytes = 0; - malloc_space->Sweep(swap_bitmaps, &freed_objects, &freed_bytes); + alloc_space->Sweep(swap_bitmaps, &freed_objects, &freed_bytes); heap_->RecordFree(freed_objects, freed_bytes); freed_objects_.FetchAndAdd(freed_objects); freed_bytes_.FetchAndAdd(freed_bytes); @@ -1278,23 +1256,6 @@ inline bool MarkSweep::IsMarked(const Object* object) const return heap_->GetMarkBitmap()->Test(object); } -void MarkSweep::UnBindBitmaps() { - TimingLogger::ScopedSplit split("UnBindBitmaps", &timings_); - for (const auto& space : GetHeap()->GetContinuousSpaces()) { - if (space->IsMallocSpace()) { - space::MallocSpace* alloc_space = space->AsMallocSpace(); - if (alloc_space->temp_bitmap_.get() != NULL) { - // At this point, the temp_bitmap holds our old mark bitmap. - accounting::SpaceBitmap* new_bitmap = alloc_space->temp_bitmap_.release(); - GetHeap()->GetMarkBitmap()->ReplaceBitmap(alloc_space->mark_bitmap_.get(), new_bitmap); - CHECK_EQ(alloc_space->mark_bitmap_.release(), alloc_space->live_bitmap_.get()); - alloc_space->mark_bitmap_.reset(new_bitmap); - DCHECK(alloc_space->temp_bitmap_.get() == NULL); - } - } - } -} - void MarkSweep::FinishPhase() { TimingLogger::ScopedSplit split("FinishPhase", &timings_); // Can't enqueue references if we hold the mutator lock. diff --git a/runtime/gc/collector/mark_sweep.h b/runtime/gc/collector/mark_sweep.h index e2eafb5..0c27a3b 100644 --- a/runtime/gc/collector/mark_sweep.h +++ b/runtime/gc/collector/mark_sweep.h @@ -118,12 +118,6 @@ class MarkSweep : public GarbageCollector { // the image. Mark that portion of the heap as immune. virtual void BindBitmaps() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void BindLiveToMarkBitmap(space::ContinuousSpace* space) - EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_); - - void UnBindBitmaps() - EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_); - // Builds a mark stack with objects on dirty cards and recursively mark until it empties. void RecursiveMarkDirtyObjects(bool paused, byte minimum_age) EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) @@ -151,10 +145,6 @@ class MarkSweep : public GarbageCollector { void SweepArray(accounting::ObjectStack* allocation_stack_, bool swap_bitmaps) EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_); - mirror::Object* GetClearedReferences() { - return cleared_reference_list_; - } - // Blackens an object. void ScanObject(mirror::Object* obj) EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) @@ -346,12 +336,6 @@ class MarkSweep : public GarbageCollector { mirror::Object* immune_begin_; mirror::Object* immune_end_; - mirror::Object* soft_reference_list_; - mirror::Object* weak_reference_list_; - mirror::Object* finalizer_reference_list_; - mirror::Object* phantom_reference_list_; - mirror::Object* cleared_reference_list_; - // Parallel finger. AtomicInteger atomic_finger_; // Number of classes scanned, if kCountScannedTypes. diff --git a/runtime/gc/collector/semi_space.cc b/runtime/gc/collector/semi_space.cc index a273e5a..625f869 100644 --- a/runtime/gc/collector/semi_space.cc +++ b/runtime/gc/collector/semi_space.cc @@ -67,7 +67,8 @@ static constexpr bool kResetFromSpace = true; void SemiSpace::ImmuneSpace(space::ContinuousSpace* space) { // Bind live to mark bitmap if necessary. if (space->GetLiveBitmap() != space->GetMarkBitmap()) { - BindLiveToMarkBitmap(space); + CHECK(space->IsContinuousMemMapAllocSpace()); + space->AsContinuousMemMapAllocSpace()->BindLiveToMarkBitmap(); } // Add the space to the immune region. if (immune_begin_ == nullptr) { @@ -98,12 +99,13 @@ void SemiSpace::ImmuneSpace(space::ContinuousSpace* space) { void SemiSpace::BindBitmaps() { timings_.StartSplit("BindBitmaps"); - WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_); + WriterMutexLock mu(self_, *Locks::heap_bitmap_lock_); // Mark all of the spaces we never collect as immune. for (const auto& space : GetHeap()->GetContinuousSpaces()) { if (space->GetLiveBitmap() != nullptr) { if (space == to_space_) { - BindLiveToMarkBitmap(to_space_); + CHECK(to_space_->IsContinuousMemMapAllocSpace()); + to_space_->AsContinuousMemMapAllocSpace()->BindLiveToMarkBitmap(); } else if (space->GetGcRetentionPolicy() == space::kGcRetentionPolicyNeverCollect || space->GetGcRetentionPolicy() == space::kGcRetentionPolicyFullCollect // Add the main free list space and the non-moving @@ -179,8 +181,7 @@ void SemiSpace::MarkingPhase() { VLOG(heap) << "Bump pointer space only collection"; } } - Thread* self = Thread::Current(); - Locks::mutator_lock_->AssertExclusiveHeld(self); + Locks::mutator_lock_->AssertExclusiveHeld(self_); TimingLogger::ScopedSplit split("MarkingPhase", &timings_); // Need to do this with mutators paused so that somebody doesn't accidentally allocate into the // wrong space. @@ -208,7 +209,7 @@ void SemiSpace::MarkingPhase() { // the live stack during the recursive mark. timings_.NewSplit("SwapStacks"); heap_->SwapStacks(); - WriterMutexLock mu(self, *Locks::heap_bitmap_lock_); + WriterMutexLock mu(self_, *Locks::heap_bitmap_lock_); MarkRoots(); // Mark roots of immune spaces. UpdateAndMarkModUnion(); @@ -309,10 +310,9 @@ void SemiSpace::MarkReachableObjects() { void SemiSpace::ReclaimPhase() { TimingLogger::ScopedSplit split("ReclaimPhase", &timings_); - Thread* self = Thread::Current(); - ProcessReferences(self); + ProcessReferences(self_); { - ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_); + ReaderMutexLock mu(self_, *Locks::heap_bitmap_lock_); SweepSystemWeaks(); } // Record freed memory. @@ -333,7 +333,7 @@ void SemiSpace::ReclaimPhase() { timings_.EndSplit(); { - WriterMutexLock mu(self, *Locks::heap_bitmap_lock_); + WriterMutexLock mu(self_, *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 @@ -343,7 +343,8 @@ void SemiSpace::ReclaimPhase() { SwapBitmaps(); timings_.EndSplit(); // Unbind the live and mark bitmaps. - UnBindBitmaps(); + TimingLogger::ScopedSplit split("UnBindBitmaps", &timings_); + GetHeap()->UnBindBitmaps(); } // Release the memory used by the from space. if (kResetFromSpace) { @@ -534,14 +535,6 @@ void SemiSpace::MarkRoots() { timings_.EndSplit(); } -void SemiSpace::BindLiveToMarkBitmap(space::ContinuousSpace* space) { - CHECK(space->IsMallocSpace()); - space::MallocSpace* alloc_space = space->AsMallocSpace(); - accounting::SpaceBitmap* live_bitmap = space->GetLiveBitmap(); - accounting::SpaceBitmap* mark_bitmap = alloc_space->BindLiveToMarkBitmap(); - GetHeap()->GetMarkBitmap()->ReplaceBitmap(mark_bitmap, live_bitmap); -} - mirror::Object* SemiSpace::MarkedForwardingAddressCallback(Object* object, void* arg) { return reinterpret_cast<SemiSpace*>(arg)->GetMarkedForwardAddress(object); } @@ -552,7 +545,7 @@ void SemiSpace::SweepSystemWeaks() { timings_.EndSplit(); } -bool SemiSpace::ShouldSweepSpace(space::MallocSpace* space) const { +bool SemiSpace::ShouldSweepSpace(space::ContinuousSpace* space) const { return space != from_space_ && space != to_space_ && !IsImmuneSpace(space); } @@ -560,16 +553,16 @@ void SemiSpace::Sweep(bool swap_bitmaps) { DCHECK(mark_stack_->IsEmpty()); TimingLogger::ScopedSplit("Sweep", &timings_); for (const auto& space : GetHeap()->GetContinuousSpaces()) { - if (space->IsMallocSpace()) { - space::MallocSpace* malloc_space = space->AsMallocSpace(); - if (!ShouldSweepSpace(malloc_space)) { + if (space->IsContinuousMemMapAllocSpace()) { + space::ContinuousMemMapAllocSpace* alloc_space = space->AsContinuousMemMapAllocSpace(); + if (!ShouldSweepSpace(alloc_space)) { continue; } TimingLogger::ScopedSplit split( - malloc_space->IsZygoteSpace() ? "SweepZygoteSpace" : "SweepAllocSpace", &timings_); + alloc_space->IsZygoteSpace() ? "SweepZygoteSpace" : "SweepAllocSpace", &timings_); size_t freed_objects = 0; size_t freed_bytes = 0; - malloc_space->Sweep(swap_bitmaps, &freed_objects, &freed_bytes); + alloc_space->Sweep(swap_bitmaps, &freed_objects, &freed_bytes); heap_->RecordFree(freed_objects, freed_bytes); freed_objects_.FetchAndAdd(freed_objects); freed_bytes_.FetchAndAdd(freed_bytes); @@ -664,20 +657,6 @@ inline Object* SemiSpace::GetMarkedForwardAddress(mirror::Object* obj) const return heap_->GetMarkBitmap()->Test(obj) ? obj : nullptr; } -void SemiSpace::UnBindBitmaps() { - TimingLogger::ScopedSplit split("UnBindBitmaps", &timings_); - for (const auto& space : GetHeap()->GetContinuousSpaces()) { - if (space->IsMallocSpace()) { - space::MallocSpace* alloc_space = space->AsMallocSpace(); - if (alloc_space->HasBoundBitmaps()) { - alloc_space->UnBindBitmaps(); - heap_->GetMarkBitmap()->ReplaceBitmap(alloc_space->GetLiveBitmap(), - alloc_space->GetMarkBitmap()); - } - } - } -} - void SemiSpace::SetToSpace(space::ContinuousMemMapAllocSpace* to_space) { DCHECK(to_space != nullptr); to_space_ = to_space; @@ -690,7 +669,6 @@ void SemiSpace::SetFromSpace(space::ContinuousMemMapAllocSpace* from_space) { void SemiSpace::FinishPhase() { TimingLogger::ScopedSplit split("FinishPhase", &timings_); - // Can't enqueue references if we hold the mutator lock. Heap* heap = GetHeap(); timings_.NewSplit("PostGcVerification"); heap->PostGcVerification(this); diff --git a/runtime/gc/collector/semi_space.h b/runtime/gc/collector/semi_space.h index bf129a3..f81a7c2 100644 --- a/runtime/gc/collector/semi_space.h +++ b/runtime/gc/collector/semi_space.h @@ -114,9 +114,6 @@ class SemiSpace : public GarbageCollector { // the image. Mark that portion of the heap as immune. virtual void BindBitmaps() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void BindLiveToMarkBitmap(space::ContinuousSpace* space) - EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_); - void UnBindBitmaps() EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_); @@ -171,7 +168,7 @@ class SemiSpace : public GarbageCollector { void ResizeMarkStack(size_t new_size); // Returns true if we should sweep the space. - virtual bool ShouldSweepSpace(space::MallocSpace* space) const; + virtual bool ShouldSweepSpace(space::ContinuousSpace* space) const; // Returns how many threads we should use for the current GC phase based on if we are paused, // whether or not we care about pauses. diff --git a/runtime/gc/collector/sticky_mark_sweep.cc b/runtime/gc/collector/sticky_mark_sweep.cc index c562e8c..30f3753 100644 --- a/runtime/gc/collector/sticky_mark_sweep.cc +++ b/runtime/gc/collector/sticky_mark_sweep.cc @@ -40,10 +40,10 @@ void StickyMarkSweep::BindBitmaps() { for (const auto& space : GetHeap()->GetContinuousSpaces()) { if (space->IsMallocSpace() && space->GetGcRetentionPolicy() == space::kGcRetentionPolicyAlwaysCollect) { - BindLiveToMarkBitmap(space); + DCHECK(space->IsContinuousMemMapAllocSpace()); + space->AsContinuousMemMapAllocSpace()->BindLiveToMarkBitmap(); } } - GetHeap()->GetLargeObjectsSpace()->CopyLiveToMarked(); } diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc index 06793bf..fd98e29 100644 --- a/runtime/gc/heap.cc +++ b/runtime/gc/heap.cc @@ -44,6 +44,7 @@ #include "gc/space/large_object_space.h" #include "gc/space/rosalloc_space-inl.h" #include "gc/space/space-inl.h" +#include "gc/space/zygote_space.h" #include "heap-inl.h" #include "image.h" #include "invoke_arg_array_builder.h" @@ -485,7 +486,6 @@ void Heap::RemoveSpace(space::Space* space) { DCHECK(it != alloc_spaces_.end()); alloc_spaces_.erase(it); } - delete space; } void Heap::RegisterGCAllocation(size_t bytes) { @@ -605,7 +605,7 @@ struct SoftReferenceArgs { }; mirror::Object* Heap::PreserveSoftReferenceCallback(mirror::Object* obj, void* arg) { - SoftReferenceArgs* args = reinterpret_cast<SoftReferenceArgs*>(arg); + SoftReferenceArgs* args = reinterpret_cast<SoftReferenceArgs*>(arg); // TODO: Not preserve all soft references. return args->recursive_mark_callback_(obj, args->arg_); } @@ -749,7 +749,7 @@ void Heap::Trim() { uint64_t total_alloc_space_size = 0; uint64_t managed_reclaimed = 0; for (const auto& space : continuous_spaces_) { - if (space->IsMallocSpace() && !space->IsZygoteSpace()) { + if (space->IsMallocSpace()) { gc::space::MallocSpace* alloc_space = space->AsMallocSpace(); total_alloc_space_size += alloc_space->Size(); managed_reclaimed += alloc_space->Trim(); @@ -1198,8 +1198,10 @@ void Heap::TransitionCollector(CollectorType collector_type) { DCHECK(allocator_mem_map_.get() == nullptr); allocator_mem_map_.reset(main_space_->ReleaseMemMap()); madvise(main_space_->Begin(), main_space_->Size(), MADV_DONTNEED); - // RemoveSpace deletes the removed space. - RemoveSpace(main_space_); + // RemoveSpace does not delete the removed space. + space::Space* old_space = main_space_; + RemoveSpace(old_space); + delete old_space; break; } case kCollectorTypeMS: @@ -1349,7 +1351,7 @@ class ZygoteCompactingCollector : public collector::SemiSpace { } } - virtual bool ShouldSweepSpace(space::MallocSpace* space) const { + virtual bool ShouldSweepSpace(space::ContinuousSpace* space) const { // Don't sweep any spaces since we probably blasted the internal accounting of the free list // allocator. return false; @@ -1389,6 +1391,17 @@ class ZygoteCompactingCollector : public collector::SemiSpace { } }; +void Heap::UnBindBitmaps() { + for (const auto& space : GetContinuousSpaces()) { + if (space->IsContinuousMemMapAllocSpace()) { + space::ContinuousMemMapAllocSpace* alloc_space = space->AsContinuousMemMapAllocSpace(); + if (alloc_space->HasBoundBitmaps()) { + alloc_space->UnBindBitmaps(); + } + } + } +} + void Heap::PreZygoteFork() { static Mutex zygote_creation_lock_("zygote creation lock", kZygoteCreationLock); Thread* self = Thread::Current(); @@ -1424,30 +1437,28 @@ void Heap::PreZygoteFork() { non_moving_space_->SetLimit(target_space.Limit()); VLOG(heap) << "Zygote size " << non_moving_space_->Size() << " bytes"; } + // Save the old space so that we can remove it after we complete creating the zygote space. + space::MallocSpace* old_alloc_space = non_moving_space_; // Turn the current alloc space into a zygote space and obtain the new alloc space composed of - // the remaining available heap memory. - space::MallocSpace* zygote_space = non_moving_space_; - main_space_ = non_moving_space_->CreateZygoteSpace("alloc space", low_memory_mode_); + // the remaining available space. + // Remove the old space before creating the zygote space since creating the zygote space sets + // the old alloc space's bitmaps to nullptr. + RemoveSpace(old_alloc_space); + space::ZygoteSpace* zygote_space = old_alloc_space->CreateZygoteSpace("alloc space", + low_memory_mode_, + &main_space_); + delete old_alloc_space; + CHECK(zygote_space != nullptr) << "Failed creating zygote space"; + AddSpace(zygote_space, false); + CHECK(main_space_ != nullptr); if (main_space_->IsRosAllocSpace()) { rosalloc_space_ = main_space_->AsRosAllocSpace(); } else if (main_space_->IsDlMallocSpace()) { dlmalloc_space_ = main_space_->AsDlMallocSpace(); } main_space_->SetFootprintLimit(main_space_->Capacity()); - // Change the GC retention policy of the zygote space to only collect when full. - zygote_space->SetGcRetentionPolicy(space::kGcRetentionPolicyFullCollect); AddSpace(main_space_); have_zygote_space_ = true; - // Remove the zygote space from alloc_spaces_ array since not doing so causes crashes in - // GetObjectsAllocated. This happens because the bin packing blows away the internal accounting - // stored in between objects. - if (zygote_space->IsAllocSpace()) { - // TODO: Refactor zygote spaces to be a new space type to avoid more of these types of issues. - auto it = std::find(alloc_spaces_.begin(), alloc_spaces_.end(), zygote_space->AsAllocSpace()); - CHECK(it != alloc_spaces_.end()); - alloc_spaces_.erase(it); - zygote_space->InvalidateAllocator(); - } // Create the zygote space mod union table. accounting::ModUnionTable* mod_union_table = new accounting::ModUnionTableCardCache("zygote space mod-union table", this, zygote_space); diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h index 52138d1..fd7a614 100644 --- a/runtime/gc/heap.h +++ b/runtime/gc/heap.h @@ -467,6 +467,9 @@ class Heap { void MarkAllocStackAsLive(accounting::ObjectStack* stack) EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_); + // Unbind any bound bitmaps. + void UnBindBitmaps() EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_); + // DEPRECATED: Should remove in "near" future when support for multiple image spaces is added. // Assumes there is only one image space. space::ImageSpace* GetImageSpace() const; diff --git a/runtime/gc/space/dlmalloc_space.cc b/runtime/gc/space/dlmalloc_space.cc index 981af53..9ae6a33 100644 --- a/runtime/gc/space/dlmalloc_space.cc +++ b/runtime/gc/space/dlmalloc_space.cc @@ -287,6 +287,7 @@ uint64_t DlMallocSpace::GetObjectsAllocated() { } void DlMallocSpace::Clear() { + // TODO: Delete and create new mspace here. madvise(GetMemMap()->Begin(), GetMemMap()->Size(), MADV_DONTNEED); GetLiveBitmap()->Clear(); GetMarkBitmap()->Clear(); diff --git a/runtime/gc/space/dlmalloc_space.h b/runtime/gc/space/dlmalloc_space.h index 671d2b2..24308f7 100644 --- a/runtime/gc/space/dlmalloc_space.h +++ b/runtime/gc/space/dlmalloc_space.h @@ -97,10 +97,6 @@ class DlMallocSpace : public MallocSpace { virtual void Clear(); - virtual void InvalidateAllocator() { - mspace_for_alloc_ = nullptr; - } - virtual bool IsDlMallocSpace() const { return true; } diff --git a/runtime/gc/space/image_space.h b/runtime/gc/space/image_space.h index 78a83c9..c3f0ae6 100644 --- a/runtime/gc/space/image_space.h +++ b/runtime/gc/space/image_space.h @@ -29,10 +29,6 @@ namespace space { // An image space is a space backed with a memory mapped image. class ImageSpace : public MemMapSpace { public: - bool CanAllocateInto() const { - return false; - } - SpaceType GetType() const { return kSpaceTypeImageSpace; } @@ -75,6 +71,10 @@ class ImageSpace : public MemMapSpace { void Dump(std::ostream& os) const; + // Sweeping image spaces is a NOP. + void Sweep(bool /* swap_bitmaps */, size_t* /* freed_objects */, size_t* /* freed_bytes */) { + } + private: // Tries to initialize an ImageSpace from the given image path, // returning NULL on error. diff --git a/runtime/gc/space/malloc_space.cc b/runtime/gc/space/malloc_space.cc index 2b2b26e..9ca4eac 100644 --- a/runtime/gc/space/malloc_space.cc +++ b/runtime/gc/space/malloc_space.cc @@ -19,6 +19,8 @@ #include "gc/accounting/card_table-inl.h" #include "gc/accounting/space_bitmap-inl.h" #include "gc/heap.h" +#include "gc/space/space-inl.h" +#include "gc/space/zygote_space.h" #include "mirror/class-inl.h" #include "mirror/object-inl.h" #include "runtime.h" @@ -33,22 +35,27 @@ namespace space { size_t MallocSpace::bitmap_index_ = 0; MallocSpace::MallocSpace(const std::string& name, MemMap* mem_map, - byte* begin, byte* end, byte* limit, size_t growth_limit) + byte* begin, byte* end, byte* limit, size_t growth_limit, + bool create_bitmaps) : ContinuousMemMapAllocSpace(name, mem_map, begin, end, limit, kGcRetentionPolicyAlwaysCollect), recent_free_pos_(0), lock_("allocation space lock", kAllocSpaceLock), growth_limit_(growth_limit) { - size_t bitmap_index = bitmap_index_++; - static const uintptr_t kGcCardSize = static_cast<uintptr_t>(accounting::CardTable::kCardSize); - CHECK(IsAligned<kGcCardSize>(reinterpret_cast<uintptr_t>(mem_map->Begin()))); - CHECK(IsAligned<kGcCardSize>(reinterpret_cast<uintptr_t>(mem_map->End()))); - live_bitmap_.reset(accounting::SpaceBitmap::Create( - StringPrintf("allocspace %s live-bitmap %d", name.c_str(), static_cast<int>(bitmap_index)), - Begin(), Capacity())); - DCHECK(live_bitmap_.get() != NULL) << "could not create allocspace live bitmap #" << bitmap_index; - mark_bitmap_.reset(accounting::SpaceBitmap::Create( - StringPrintf("allocspace %s mark-bitmap %d", name.c_str(), static_cast<int>(bitmap_index)), - Begin(), Capacity())); - DCHECK(live_bitmap_.get() != NULL) << "could not create allocspace mark bitmap #" << bitmap_index; + if (create_bitmaps) { + size_t bitmap_index = bitmap_index_++; + static const uintptr_t kGcCardSize = static_cast<uintptr_t>(accounting::CardTable::kCardSize); + CHECK(IsAligned<kGcCardSize>(reinterpret_cast<uintptr_t>(mem_map->Begin()))); + CHECK(IsAligned<kGcCardSize>(reinterpret_cast<uintptr_t>(mem_map->End()))); + live_bitmap_.reset(accounting::SpaceBitmap::Create( + StringPrintf("allocspace %s live-bitmap %d", name.c_str(), static_cast<int>(bitmap_index)), + Begin(), Capacity())); + DCHECK(live_bitmap_.get() != NULL) << "could not create allocspace live bitmap #" + << bitmap_index; + mark_bitmap_.reset(accounting::SpaceBitmap::Create( + StringPrintf("allocspace %s mark-bitmap %d", name.c_str(), static_cast<int>(bitmap_index)), + Begin(), Capacity())); + DCHECK(live_bitmap_.get() != NULL) << "could not create allocspace mark bitmap #" + << bitmap_index; + } for (auto& freed : recent_freed_objects_) { freed.first = nullptr; freed.second = nullptr; @@ -154,29 +161,8 @@ void* MallocSpace::MoreCore(intptr_t increment) { return original_end; } -// Returns the old mark bitmap. -accounting::SpaceBitmap* MallocSpace::BindLiveToMarkBitmap() { - accounting::SpaceBitmap* live_bitmap = GetLiveBitmap(); - accounting::SpaceBitmap* mark_bitmap = mark_bitmap_.release(); - temp_bitmap_.reset(mark_bitmap); - mark_bitmap_.reset(live_bitmap); - return mark_bitmap; -} - -bool MallocSpace::HasBoundBitmaps() const { - return temp_bitmap_.get() != nullptr; -} - -void MallocSpace::UnBindBitmaps() { - CHECK(HasBoundBitmaps()); - // At this point, the temp_bitmap holds our old mark bitmap. - accounting::SpaceBitmap* new_bitmap = temp_bitmap_.release(); - CHECK_EQ(mark_bitmap_.release(), live_bitmap_.get()); - mark_bitmap_.reset(new_bitmap); - DCHECK(temp_bitmap_.get() == NULL); -} - -MallocSpace* MallocSpace::CreateZygoteSpace(const char* alloc_space_name, bool low_memory_mode) { +ZygoteSpace* MallocSpace::CreateZygoteSpace(const char* alloc_space_name, bool low_memory_mode, + MallocSpace** out_malloc_space) { // For RosAlloc, revoke thread local runs before creating a new // alloc space so that we won't mix thread local runs from different // alloc spaces. @@ -220,15 +206,23 @@ MallocSpace* MallocSpace::CreateZygoteSpace(const char* alloc_space_name, bool l if (capacity - initial_size > 0) { CHECK_MEMORY_CALL(mprotect, (end, capacity - initial_size, PROT_NONE), alloc_space_name); } - MallocSpace* alloc_space = CreateInstance(alloc_space_name, mem_map.release(), allocator, - end_, end, limit_, growth_limit); + *out_malloc_space = CreateInstance(alloc_space_name, mem_map.release(), allocator, end_, end, + limit_, growth_limit); SetLimit(End()); live_bitmap_->SetHeapLimit(reinterpret_cast<uintptr_t>(End())); CHECK_EQ(live_bitmap_->HeapLimit(), reinterpret_cast<uintptr_t>(End())); mark_bitmap_->SetHeapLimit(reinterpret_cast<uintptr_t>(End())); CHECK_EQ(mark_bitmap_->HeapLimit(), reinterpret_cast<uintptr_t>(End())); - VLOG(heap) << "zygote space creation done"; - return alloc_space; + + // Create the actual zygote space. + ZygoteSpace* zygote_space = ZygoteSpace::Create("Zygote space", ReleaseMemMap(), + live_bitmap_.release(), mark_bitmap_.release()); + if (UNLIKELY(zygote_space == nullptr)) { + VLOG(heap) << "Failed creating zygote space from space " << GetName(); + } else { + VLOG(heap) << "zygote space creation done"; + } + return zygote_space; } void MallocSpace::Dump(std::ostream& os) const { @@ -239,24 +233,16 @@ void MallocSpace::Dump(std::ostream& os) const { << ",name=\"" << GetName() << "\"]"; } -struct SweepCallbackContext { - bool swap_bitmaps; - Heap* heap; - space::MallocSpace* space; - Thread* self; - size_t freed_objects; - size_t freed_bytes; -}; - -static void SweepCallback(size_t num_ptrs, mirror::Object** ptrs, void* arg) { +void MallocSpace::SweepCallback(size_t num_ptrs, mirror::Object** ptrs, void* arg) { SweepCallbackContext* context = static_cast<SweepCallbackContext*>(arg); - space::AllocSpace* space = context->space; + DCHECK(context->space->IsMallocSpace()); + space::MallocSpace* space = context->space->AsMallocSpace(); Thread* self = context->self; Locks::heap_bitmap_lock_->AssertExclusiveHeld(self); // If the bitmaps aren't swapped we need to clear the bits since the GC isn't going to re-swap // the bitmaps as an optimization. if (!context->swap_bitmaps) { - accounting::SpaceBitmap* bitmap = context->space->GetLiveBitmap(); + accounting::SpaceBitmap* bitmap = space->GetLiveBitmap(); for (size_t i = 0; i < num_ptrs; ++i) { bitmap->Clear(ptrs[i]); } @@ -268,54 +254,6 @@ static void SweepCallback(size_t num_ptrs, mirror::Object** ptrs, void* arg) { context->freed_bytes += space->FreeList(self, num_ptrs, ptrs); } -static void ZygoteSweepCallback(size_t num_ptrs, mirror::Object** ptrs, void* arg) { - SweepCallbackContext* context = static_cast<SweepCallbackContext*>(arg); - Locks::heap_bitmap_lock_->AssertExclusiveHeld(context->self); - accounting::CardTable* card_table = context->heap->GetCardTable(); - // If the bitmaps aren't swapped we need to clear the bits since the GC isn't going to re-swap - // the bitmaps as an optimization. - if (!context->swap_bitmaps) { - accounting::SpaceBitmap* bitmap = context->space->GetLiveBitmap(); - for (size_t i = 0; i < num_ptrs; ++i) { - bitmap->Clear(ptrs[i]); - } - } - // We don't free any actual memory to avoid dirtying the shared zygote pages. - for (size_t i = 0; i < num_ptrs; ++i) { - // Need to mark the card since this will update the mod-union table next GC cycle. - card_table->MarkCard(ptrs[i]); - } -} - -void MallocSpace::Sweep(bool swap_bitmaps, size_t* freed_objects, size_t* freed_bytes) { - DCHECK(freed_objects != nullptr); - DCHECK(freed_bytes != nullptr); - accounting::SpaceBitmap* live_bitmap = GetLiveBitmap(); - accounting::SpaceBitmap* mark_bitmap = GetMarkBitmap(); - // If the bitmaps are bound then sweeping this space clearly won't do anything. - if (live_bitmap == mark_bitmap) { - return; - } - SweepCallbackContext scc; - scc.swap_bitmaps = swap_bitmaps; - scc.heap = Runtime::Current()->GetHeap(); - scc.self = Thread::Current(); - scc.space = this; - scc.freed_objects = 0; - scc.freed_bytes = 0; - if (swap_bitmaps) { - std::swap(live_bitmap, mark_bitmap); - } - // Bitmaps are pre-swapped for optimization which enables sweeping with the heap unlocked. - accounting::SpaceBitmap::SweepWalk(*live_bitmap, *mark_bitmap, - reinterpret_cast<uintptr_t>(Begin()), - reinterpret_cast<uintptr_t>(End()), - IsZygoteSpace() ? &ZygoteSweepCallback : &SweepCallback, - reinterpret_cast<void*>(&scc)); - *freed_objects += scc.freed_objects; - *freed_bytes += scc.freed_bytes; -} - } // namespace space } // namespace gc } // namespace art diff --git a/runtime/gc/space/malloc_space.h b/runtime/gc/space/malloc_space.h index 7681b6d..58cfe8b 100644 --- a/runtime/gc/space/malloc_space.h +++ b/runtime/gc/space/malloc_space.h @@ -31,6 +31,8 @@ namespace collector { namespace space { +class ZygoteSpace; + // TODO: Remove define macro #define CHECK_MEMORY_CALL(call, args, what) \ do { \ @@ -41,19 +43,13 @@ namespace space { } \ } while (false) -// const bool kUseRosAlloc = true; - // A common parent of DlMallocSpace and RosAllocSpace. class MallocSpace : public ContinuousMemMapAllocSpace { public: typedef void(*WalkCallback)(void *start, void *end, size_t num_bytes, void* callback_arg); SpaceType GetType() const { - if (GetGcRetentionPolicy() == kGcRetentionPolicyFullCollect) { - return kSpaceTypeZygoteSpace; - } else { - return kSpaceTypeAllocSpace; - } + return kSpaceTypeMallocSpace; } // Allocate num_bytes without allowing the underlying space to grow. @@ -109,14 +105,6 @@ class MallocSpace : public ContinuousMemMapAllocSpace { return GetMemMap()->Size(); } - accounting::SpaceBitmap* GetLiveBitmap() const { - return live_bitmap_.get(); - } - - accounting::SpaceBitmap* GetMarkBitmap() const { - return mark_bitmap_.get(); - } - void Dump(std::ostream& os) const; void SetGrowthLimit(size_t growth_limit); @@ -127,33 +115,20 @@ class MallocSpace : public ContinuousMemMapAllocSpace { virtual MallocSpace* CreateInstance(const std::string& name, MemMap* mem_map, void* allocator, byte* begin, byte* end, byte* limit, size_t growth_limit) = 0; - // Turn ourself into a zygote space and return a new alloc space - // which has our unused memory. When true, the low memory mode - // argument specifies that the heap wishes the created space to be - // more aggressive in releasing unused pages. - MallocSpace* CreateZygoteSpace(const char* alloc_space_name, bool low_memory_mode); - + // Splits ourself into a zygote space and new malloc space which has our unused memory. When true, + // the low memory mode argument specifies that the heap wishes the created space to be more + // aggressive in releasing unused pages. Invalidates the space its called on. + ZygoteSpace* CreateZygoteSpace(const char* alloc_space_name, bool low_memory_mode, + MallocSpace** out_malloc_space) NO_THREAD_SAFETY_ANALYSIS; virtual uint64_t GetBytesAllocated() = 0; virtual uint64_t GetObjectsAllocated() = 0; - // Returns the old mark bitmap. - accounting::SpaceBitmap* BindLiveToMarkBitmap(); - bool HasBoundBitmaps() const; - void UnBindBitmaps(); - // Returns the class of a recently freed object. mirror::Class* FindRecentFreedObject(const mirror::Object* obj); - // Used to ensure that failure happens when you free / allocate into an invalidated space. If we - // don't do this we may get heap corruption instead of a segfault at null. - virtual void InvalidateAllocator() = 0; - - // Sweep the references in the malloc space. - void Sweep(bool swap_bitmaps, size_t* freed_objects, size_t* freed_bytes); - protected: MallocSpace(const std::string& name, MemMap* mem_map, byte* begin, byte* end, - byte* limit, size_t growth_limit); + byte* limit, size_t growth_limit, bool create_bitmaps = true); static MemMap* CreateMemMap(const std::string& name, size_t starting_size, size_t* initial_size, size_t* growth_limit, size_t* capacity, byte* requested_begin); @@ -166,9 +141,9 @@ class MallocSpace : public ContinuousMemMapAllocSpace { void RegisterRecentFree(mirror::Object* ptr) EXCLUSIVE_LOCKS_REQUIRED(lock_); - UniquePtr<accounting::SpaceBitmap> live_bitmap_; - UniquePtr<accounting::SpaceBitmap> mark_bitmap_; - UniquePtr<accounting::SpaceBitmap> temp_bitmap_; + virtual accounting::SpaceBitmap::SweepCallback* GetSweepCallback() { + return &SweepCallback; + } // Recent allocation buffer. static constexpr size_t kRecentFreeCount = kDebugSpaces ? (1 << 16) : 0; @@ -190,9 +165,9 @@ class MallocSpace : public ContinuousMemMapAllocSpace { // one time by a call to ClearGrowthLimit. size_t growth_limit_; - friend class collector::MarkSweep; - private: + static void SweepCallback(size_t num_ptrs, mirror::Object** ptrs, void* arg); + DISALLOW_COPY_AND_ASSIGN(MallocSpace); }; diff --git a/runtime/gc/space/rosalloc_space.cc b/runtime/gc/space/rosalloc_space.cc index e5993f6..177e38e 100644 --- a/runtime/gc/space/rosalloc_space.cc +++ b/runtime/gc/space/rosalloc_space.cc @@ -312,6 +312,7 @@ void RosAllocSpace::RevokeAllThreadLocalBuffers() { } void RosAllocSpace::Clear() { + // TODO: Delete and create new mspace here. madvise(GetMemMap()->Begin(), GetMemMap()->Size(), MADV_DONTNEED); GetLiveBitmap()->Clear(); GetMarkBitmap()->Clear(); diff --git a/runtime/gc/space/rosalloc_space.h b/runtime/gc/space/rosalloc_space.h index 6720976..555eb3c 100644 --- a/runtime/gc/space/rosalloc_space.h +++ b/runtime/gc/space/rosalloc_space.h @@ -95,10 +95,6 @@ class RosAllocSpace : public MallocSpace { // Returns the class of a recently freed object. mirror::Class* FindRecentFreedObject(const mirror::Object* obj); - virtual void InvalidateAllocator() { - rosalloc_for_alloc_ = NULL; - } - virtual bool IsRosAllocSpace() const { return true; } diff --git a/runtime/gc/space/space-inl.h b/runtime/gc/space/space-inl.h index 0c1d7a2..e94c44e 100644 --- a/runtime/gc/space/space-inl.h +++ b/runtime/gc/space/space-inl.h @@ -32,7 +32,7 @@ inline ImageSpace* Space::AsImageSpace() { } inline MallocSpace* Space::AsMallocSpace() { - DCHECK(GetType() == kSpaceTypeAllocSpace || GetType() == kSpaceTypeZygoteSpace); + DCHECK(GetType() == kSpaceTypeMallocSpace); DCHECK(IsDlMallocSpace() || IsRosAllocSpace()); return down_cast<MallocSpace*>(down_cast<MemMapSpace*>(this)); } diff --git a/runtime/gc/space/space.cc b/runtime/gc/space/space.cc index f8ba6b3..5478d5b 100644 --- a/runtime/gc/space/space.cc +++ b/runtime/gc/space/space.cc @@ -17,6 +17,9 @@ #include "space.h" #include "base/logging.h" +#include "gc/accounting/heap_bitmap.h" +#include "runtime.h" +#include "thread-inl.h" namespace art { namespace gc { @@ -41,6 +44,59 @@ DiscontinuousSpace::DiscontinuousSpace(const std::string& name, mark_objects_(new accounting::ObjectSet("large marked objects")) { } +void ContinuousMemMapAllocSpace::Sweep(bool swap_bitmaps, size_t* freed_objects, size_t* freed_bytes) { + DCHECK(freed_objects != nullptr); + DCHECK(freed_bytes != nullptr); + accounting::SpaceBitmap* live_bitmap = GetLiveBitmap(); + accounting::SpaceBitmap* mark_bitmap = GetMarkBitmap(); + // If the bitmaps are bound then sweeping this space clearly won't do anything. + if (live_bitmap == mark_bitmap) { + return; + } + SweepCallbackContext scc; + scc.swap_bitmaps = swap_bitmaps; + scc.heap = Runtime::Current()->GetHeap(); + scc.self = Thread::Current(); + scc.space = this; + scc.freed_objects = 0; + scc.freed_bytes = 0; + if (swap_bitmaps) { + std::swap(live_bitmap, mark_bitmap); + } + // Bitmaps are pre-swapped for optimization which enables sweeping with the heap unlocked. + accounting::SpaceBitmap::SweepWalk(*live_bitmap, *mark_bitmap, + reinterpret_cast<uintptr_t>(Begin()), + reinterpret_cast<uintptr_t>(End()), + GetSweepCallback(), + reinterpret_cast<void*>(&scc)); + *freed_objects += scc.freed_objects; + *freed_bytes += scc.freed_bytes; +} + +// Returns the old mark bitmap. +void ContinuousMemMapAllocSpace::BindLiveToMarkBitmap() { + CHECK(!HasBoundBitmaps()); + accounting::SpaceBitmap* live_bitmap = GetLiveBitmap(); + accounting::SpaceBitmap* mark_bitmap = mark_bitmap_.release(); + Runtime::Current()->GetHeap()->GetMarkBitmap()->ReplaceBitmap(mark_bitmap, live_bitmap); + temp_bitmap_.reset(mark_bitmap); + mark_bitmap_.reset(live_bitmap); +} + +bool ContinuousMemMapAllocSpace::HasBoundBitmaps() const { + return temp_bitmap_.get() != nullptr; +} + +void ContinuousMemMapAllocSpace::UnBindBitmaps() { + CHECK(HasBoundBitmaps()); + // At this point, the temp_bitmap holds our old mark bitmap. + accounting::SpaceBitmap* new_bitmap = temp_bitmap_.release(); + Runtime::Current()->GetHeap()->GetMarkBitmap()->ReplaceBitmap(mark_bitmap_.get(), new_bitmap); + CHECK_EQ(mark_bitmap_.release(), live_bitmap_.get()); + mark_bitmap_.reset(new_bitmap); + DCHECK(temp_bitmap_.get() == nullptr); +} + } // namespace space } // namespace gc } // namespace art diff --git a/runtime/gc/space/space.h b/runtime/gc/space/space.h index 5292344..32230b3 100644 --- a/runtime/gc/space/space.h +++ b/runtime/gc/space/space.h @@ -44,6 +44,7 @@ namespace space { class AllocSpace; class BumpPointerSpace; +class ContinuousMemMapAllocSpace; class ContinuousSpace; class DiscontinuousSpace; class MallocSpace; @@ -51,6 +52,7 @@ class DlMallocSpace; class RosAllocSpace; class ImageSpace; class LargeObjectSpace; +class ZygoteSpace; static constexpr bool kDebugSpaces = kIsDebugBuild; @@ -68,7 +70,7 @@ std::ostream& operator<<(std::ostream& os, const GcRetentionPolicy& policy); enum SpaceType { kSpaceTypeImageSpace, - kSpaceTypeAllocSpace, + kSpaceTypeMallocSpace, kSpaceTypeZygoteSpace, kSpaceTypeBumpPointerSpace, kSpaceTypeLargeObjectSpace, @@ -91,11 +93,6 @@ class Space { return gc_retention_policy_; } - // Does the space support allocation? - virtual bool CanAllocateInto() const { - return true; - } - // Is the given object contained within this space? virtual bool Contains(const mirror::Object* obj) const = 0; @@ -111,7 +108,7 @@ class Space { // Is this a dlmalloc backed allocation space? bool IsMallocSpace() const { SpaceType type = GetType(); - return type == kSpaceTypeAllocSpace || type == kSpaceTypeZygoteSpace; + return type == kSpaceTypeMallocSpace; } MallocSpace* AsMallocSpace(); @@ -120,20 +117,24 @@ class Space { } virtual DlMallocSpace* AsDlMallocSpace() { LOG(FATAL) << "Unreachable"; - return NULL; + return nullptr; } virtual bool IsRosAllocSpace() const { return false; } virtual RosAllocSpace* AsRosAllocSpace() { LOG(FATAL) << "Unreachable"; - return NULL; + return nullptr; } // Is this the space allocated into by the Zygote and no-longer in use? bool IsZygoteSpace() const { return GetType() == kSpaceTypeZygoteSpace; } + virtual ZygoteSpace* AsZygoteSpace() { + LOG(FATAL) << "Unreachable"; + return nullptr; + } // Is this space a bump pointer space? bool IsBumpPointerSpace() const { @@ -141,7 +142,7 @@ class Space { } virtual BumpPointerSpace* AsBumpPointerSpace() { LOG(FATAL) << "Unreachable"; - return NULL; + return nullptr; } // Does this space hold large objects and implement the large object space abstraction? @@ -168,6 +169,14 @@ class Space { return nullptr; } + virtual bool IsContinuousMemMapAllocSpace() const { + return false; + } + virtual ContinuousMemMapAllocSpace* AsContinuousMemMapAllocSpace() { + LOG(FATAL) << "Unimplemented"; + return nullptr; + } + virtual ~Space() {} protected: @@ -181,6 +190,15 @@ class Space { std::string name_; protected: + struct SweepCallbackContext { + bool swap_bitmaps; + Heap* heap; + space::Space* space; + Thread* self; + size_t freed_objects; + size_t freed_bytes; + }; + // When should objects within this space be reclaimed? Not constant as we vary it in the case // of Zygote forking. GcRetentionPolicy gc_retention_policy_; @@ -378,22 +396,51 @@ class ContinuousMemMapAllocSpace : public MemMapSpace, public AllocSpace { virtual bool IsAllocSpace() const { return true; } - virtual AllocSpace* AsAllocSpace() { return this; } + virtual bool IsContinuousMemMapAllocSpace() const { + return true; + } + virtual ContinuousMemMapAllocSpace* AsContinuousMemMapAllocSpace() { + return this; + } + + bool HasBoundBitmaps() const EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_); + void BindLiveToMarkBitmap() + EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_); + void UnBindBitmaps() EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_); + virtual void Clear() { LOG(FATAL) << "Unimplemented"; } + virtual accounting::SpaceBitmap* GetLiveBitmap() const { + return live_bitmap_.get(); + } + virtual accounting::SpaceBitmap* GetMarkBitmap() const { + return mark_bitmap_.get(); + } + + virtual void Sweep(bool swap_bitmaps, size_t* freed_objects, size_t* freed_bytes); + virtual accounting::SpaceBitmap::SweepCallback* GetSweepCallback() { + LOG(FATAL) << "Unimplemented"; + return nullptr; + } + protected: + UniquePtr<accounting::SpaceBitmap> live_bitmap_; + UniquePtr<accounting::SpaceBitmap> mark_bitmap_; + UniquePtr<accounting::SpaceBitmap> temp_bitmap_; + ContinuousMemMapAllocSpace(const std::string& name, MemMap* mem_map, byte* begin, byte* end, byte* limit, GcRetentionPolicy gc_retention_policy) : MemMapSpace(name, mem_map, begin, end, limit, gc_retention_policy) { } private: + friend class gc::Heap; DISALLOW_COPY_AND_ASSIGN(ContinuousMemMapAllocSpace); }; diff --git a/runtime/gc/space/space_test.cc b/runtime/gc/space/space_test.cc index b1be9d8..427d547 100644 --- a/runtime/gc/space/space_test.cc +++ b/runtime/gc/space/space_test.cc @@ -16,6 +16,7 @@ #include "dlmalloc_space.h" #include "large_object_space.h" +#include "zygote_space.h" #include "common_test.h" #include "globals.h" @@ -179,7 +180,16 @@ void SpaceTest::ZygoteSpaceTestBody(CreateSpaceFn create_space) { // Make sure that the zygote space isn't directly at the start of the space. space->Alloc(self, 1U * MB, &dummy); - space = space->CreateZygoteSpace("alloc space", Runtime::Current()->GetHeap()->IsLowMemoryMode()); + + gc::Heap* heap = Runtime::Current()->GetHeap(); + space::Space* old_space = space; + heap->RemoveSpace(old_space); + space::ZygoteSpace* zygote_space = space->CreateZygoteSpace("alloc space", + heap->IsLowMemoryMode(), + &space); + delete old_space; + // Add the zygote space. + AddSpace(zygote_space); // Make space findable to the heap, will also delete space when runtime is cleaned up AddSpace(space); diff --git a/runtime/gc/space/zygote_space.cc b/runtime/gc/space/zygote_space.cc new file mode 100644 index 0000000..a303765 --- /dev/null +++ b/runtime/gc/space/zygote_space.cc @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "zygote_space.h" + +#include "gc/accounting/card_table-inl.h" +#include "gc/accounting/space_bitmap-inl.h" +#include "gc/heap.h" +#include "thread-inl.h" +#include "utils.h" + +namespace art { +namespace gc { +namespace space { + +class CountObjectsAllocated { + public: + explicit CountObjectsAllocated(size_t* objects_allocated) + : objects_allocated_(objects_allocated) {} + + void operator()(mirror::Object* obj) const { + ++*objects_allocated_; + } + + private: + size_t* const objects_allocated_; +}; + +ZygoteSpace* ZygoteSpace::Create(const std::string& name, MemMap* mem_map, + accounting::SpaceBitmap* live_bitmap, + accounting::SpaceBitmap* mark_bitmap) { + DCHECK(live_bitmap != nullptr); + DCHECK(mark_bitmap != nullptr); + size_t objects_allocated = 0; + CountObjectsAllocated visitor(&objects_allocated); + ReaderMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_); + live_bitmap->VisitMarkedRange(reinterpret_cast<uintptr_t>(mem_map->Begin()), + reinterpret_cast<uintptr_t>(mem_map->End()), visitor); + ZygoteSpace* zygote_space = new ZygoteSpace(name, mem_map, objects_allocated); + CHECK(zygote_space->live_bitmap_.get() == nullptr); + CHECK(zygote_space->mark_bitmap_.get() == nullptr); + zygote_space->live_bitmap_.reset(live_bitmap); + zygote_space->mark_bitmap_.reset(mark_bitmap); + return zygote_space; +} + +ZygoteSpace::ZygoteSpace(const std::string& name, MemMap* mem_map, size_t objects_allocated) + : ContinuousMemMapAllocSpace(name, mem_map, mem_map->Begin(), mem_map->End(), mem_map->End(), + kGcRetentionPolicyFullCollect), + objects_allocated_(objects_allocated) { +} + +void ZygoteSpace::Dump(std::ostream& os) const { + os << GetType() + << " begin=" << reinterpret_cast<void*>(Begin()) + << ",end=" << reinterpret_cast<void*>(End()) + << ",size=" << PrettySize(Size()) + << ",name=\"" << GetName() << "\"]"; +} + +void ZygoteSpace::SweepCallback(size_t num_ptrs, mirror::Object** ptrs, void* arg) { + SweepCallbackContext* context = static_cast<SweepCallbackContext*>(arg); + DCHECK(context->space->IsZygoteSpace()); + ZygoteSpace* zygote_space = context->space->AsZygoteSpace(); + Locks::heap_bitmap_lock_->AssertExclusiveHeld(context->self); + accounting::CardTable* card_table = context->heap->GetCardTable(); + // If the bitmaps aren't swapped we need to clear the bits since the GC isn't going to re-swap + // the bitmaps as an optimization. + if (!context->swap_bitmaps) { + accounting::SpaceBitmap* bitmap = zygote_space->GetLiveBitmap(); + for (size_t i = 0; i < num_ptrs; ++i) { + bitmap->Clear(ptrs[i]); + } + } + // We don't free any actual memory to avoid dirtying the shared zygote pages. + for (size_t i = 0; i < num_ptrs; ++i) { + // Need to mark the card since this will update the mod-union table next GC cycle. + card_table->MarkCard(ptrs[i]); + } + zygote_space->objects_allocated_.FetchAndSub(num_ptrs); +} + +} // namespace space +} // namespace gc +} // namespace art diff --git a/runtime/gc/space/zygote_space.h b/runtime/gc/space/zygote_space.h new file mode 100644 index 0000000..10a5492 --- /dev/null +++ b/runtime/gc/space/zygote_space.h @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_RUNTIME_GC_SPACE_ZYGOTE_SPACE_H_ +#define ART_RUNTIME_GC_SPACE_ZYGOTE_SPACE_H_ + +#include "malloc_space.h" +#include "mem_map.h" + +namespace art { +namespace gc { + +namespace accounting { +class SpaceBitmap; +} + +namespace space { + +// An zygote space is a space which you cannot allocate into or free from. +class ZygoteSpace : public ContinuousMemMapAllocSpace { + public: + // Returns the remaining storage in the out_map field. + static ZygoteSpace* Create(const std::string& name, MemMap* mem_map, + accounting::SpaceBitmap* live_bitmap, + accounting::SpaceBitmap* mark_bitmap) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + void Dump(std::ostream& os) const; + virtual SpaceType GetType() const { + return kSpaceTypeZygoteSpace; + } + virtual ZygoteSpace* AsZygoteSpace() { + return this; + } + virtual mirror::Object* AllocWithGrowth(Thread* /*self*/, size_t /*num_bytes*/, + size_t* /*bytes_allocated*/) { + LOG(FATAL) << "Unimplemented"; + return nullptr; + } + virtual mirror::Object* Alloc(Thread* self, size_t num_bytes, size_t* bytes_allocated) { + LOG(FATAL) << "Unimplemented"; + return nullptr; + } + virtual size_t AllocationSize(const mirror::Object* obj) { + LOG(FATAL) << "Unimplemented"; + return 0; + } + virtual size_t Free(Thread* self, mirror::Object* ptr) { + LOG(FATAL) << "Unimplemented"; + return 0; + } + virtual size_t FreeList(Thread* self, size_t num_ptrs, mirror::Object** ptrs) { + LOG(FATAL) << "Unimplemented"; + return 0; + } + virtual uint64_t GetBytesAllocated() { + return Size(); + } + virtual uint64_t GetObjectsAllocated() { + return objects_allocated_; + } + + protected: + virtual accounting::SpaceBitmap::SweepCallback* GetSweepCallback() { + return &SweepCallback; + } + + private: + ZygoteSpace(const std::string& name, MemMap* mem_map, size_t objects_allocated); + static void SweepCallback(size_t num_ptrs, mirror::Object** ptrs, void* arg); + + AtomicInteger objects_allocated_; + + friend class Space; + DISALLOW_COPY_AND_ASSIGN(ZygoteSpace); +}; + +} // namespace space +} // namespace gc +} // namespace art + +#endif // ART_RUNTIME_GC_SPACE_ZYGOTE_SPACE_H_ |