summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Mathieu Chartier <mathieuc@google.com> 2014-01-13 17:19:19 -0800
committer Mathieu Chartier <mathieuc@google.com> 2014-01-31 09:45:09 -0800
commita1602f28c0e3127ad511712d4b08db89737ae901 (patch)
tree44d7abfcaa57de85fd3c3c40d5bff3173cc60387
parenta0e4b01b6b1ef5c88e340e6b2c09f83e535777a1 (diff)
Add zygote space as its own space type.
Helps prevent errors caused from doing invalid operations on the old alloc space. Removed some duplicated code in mark_sweep.cc and semi_space.cc. Change-Id: I67a772cab30d698744c918aad581053f282a4a99
-rw-r--r--runtime/Android.mk1
-rw-r--r--runtime/gc/accounting/space_bitmap.cc6
-rw-r--r--runtime/gc/collector/mark_sweep.cc59
-rw-r--r--runtime/gc/collector/mark_sweep.h16
-rw-r--r--runtime/gc/collector/semi_space.cc58
-rw-r--r--runtime/gc/collector/semi_space.h5
-rw-r--r--runtime/gc/collector/sticky_mark_sweep.cc4
-rw-r--r--runtime/gc/heap.cc53
-rw-r--r--runtime/gc/heap.h3
-rw-r--r--runtime/gc/space/dlmalloc_space.cc1
-rw-r--r--runtime/gc/space/dlmalloc_space.h4
-rw-r--r--runtime/gc/space/image_space.h8
-rw-r--r--runtime/gc/space/malloc_space.cc138
-rw-r--r--runtime/gc/space/malloc_space.h53
-rw-r--r--runtime/gc/space/rosalloc_space.cc1
-rw-r--r--runtime/gc/space/rosalloc_space.h4
-rw-r--r--runtime/gc/space/space-inl.h2
-rw-r--r--runtime/gc/space/space.cc56
-rw-r--r--runtime/gc/space/space.h69
-rw-r--r--runtime/gc/space/space_test.cc12
-rw-r--r--runtime/gc/space/zygote_space.cc98
-rw-r--r--runtime/gc/space/zygote_space.h95
22 files changed, 447 insertions, 299 deletions
diff --git a/runtime/Android.mk b/runtime/Android.mk
index 9e6d5f9e28..530488ec15 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -65,6 +65,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 99800fcccb..b831843e61 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 5d450a7d85..862d06f977 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 e2eafb5f52..0c27a3be59 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 99c726d216..ab488d6648 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
@@ -180,8 +182,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.
@@ -209,7 +210,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();
@@ -305,10 +306,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.
@@ -329,7 +329,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
@@ -339,7 +339,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) {
@@ -530,14 +531,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);
}
@@ -548,7 +541,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);
}
@@ -556,16 +549,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);
@@ -660,20 +653,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;
@@ -686,7 +665,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 bf129a301f..f81a7c2c88 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 c562e8c4a7..30f3753ab4 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 06793bf148..fd98e2917f 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 52138d1216..fd7a6145c3 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 981af53490..9ae6a33f72 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 671d2b2690..24308f7857 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 78a83c92cd..c3f0ae6574 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 2b2b26e197..9ca4eac523 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 7681b6d459..58cfe8b6b9 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 e5993f6a6f..177e38e6aa 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 6720976e5a..555eb3cf09 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 0c1d7a2769..e94c44e7f5 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 f8ba6b3e57..5478d5b1b4 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 529234412d..32230b3529 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 b1be9d8a84..427d5471d8 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 0000000000..a303765c8e
--- /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 0000000000..10a5492b30
--- /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_