summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMathieu Chartier <mathieuc@google.com>2014-01-31 18:55:35 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2014-01-31 18:55:35 +0000
commit9aeeeac4ba0b136652f213d60a5a1990a333a629 (patch)
tree9ed565fec210c69dc136223edb882a9d858e0788
parentd65c39a050af53bef5f92221619b5416b1a8822e (diff)
parenta1602f28c0e3127ad511712d4b08db89737ae901 (diff)
downloadart-9aeeeac4ba0b136652f213d60a5a1990a333a629.zip
art-9aeeeac4ba0b136652f213d60a5a1990a333a629.tar.gz
art-9aeeeac4ba0b136652f213d60a5a1990a333a629.tar.bz2
Merge "Add zygote space as its own space type."
-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 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_