A simple promotion-like mechanism.
If enabled, this mechanism moves objects that survive the first
semi-space copying collection to the non-moving space.
Bug: 11650816
Change-Id: Ia2fc902d08dc983449416f420a39449f9ed96255
diff --git a/runtime/gc/collector/semi_space.cc b/runtime/gc/collector/semi_space.cc
index 3939354..31a3f35 100644
--- a/runtime/gc/collector/semi_space.cc
+++ b/runtime/gc/collector/semi_space.cc
@@ -78,6 +78,8 @@
static constexpr bool kProtectFromSpace = true;
static constexpr bool kResetFromSpace = true;
+// TODO: move this to a new file as a new garbage collector?
+static constexpr bool kEnableSimplePromo = false;
// TODO: Unduplicate logic.
void SemiSpace::ImmuneSpace(space::ContinuousSpace* space) {
@@ -134,7 +136,9 @@
finalizer_reference_list_(nullptr),
phantom_reference_list_(nullptr),
cleared_reference_list_(nullptr),
- self_(nullptr) {
+ self_(nullptr),
+ last_gc_to_space_end_(nullptr),
+ bytes_promoted_(0) {
}
void SemiSpace::InitializePhase() {
@@ -169,6 +173,17 @@
// Need to do this with mutators paused so that somebody doesn't accidentally allocate into the
// wrong space.
heap_->SwapSemiSpaces();
+ if (kEnableSimplePromo) {
+ // If last_gc_to_space_end_ is out of the bounds of the from-space
+ // (the to-space from last GC), then point it to the beginning of
+ // the from-space. For example, the very first GC or the
+ // pre-zygote compaction.
+ if (!from_space_->HasAddress(reinterpret_cast<mirror::Object*>(last_gc_to_space_end_))) {
+ last_gc_to_space_end_ = from_space_->Begin();
+ }
+ // Reset this before the marking starts below.
+ bytes_promoted_ = 0;
+ }
// Assume the cleared space is already empty.
BindBitmaps();
// Process dirty cards and add dirty cards to mod-union tables.
@@ -268,6 +283,13 @@
} else {
mprotect(from_space_->Begin(), from_space_->Capacity(), PROT_READ);
}
+
+ if (kEnableSimplePromo) {
+ // Record the end (top) of the to space so we can distinguish
+ // between objects that were allocated since the last GC and the
+ // older objects.
+ last_gc_to_space_end_ = to_space_->End();
+ }
}
void SemiSpace::ResizeMarkStack(size_t new_size) {
@@ -308,11 +330,38 @@
if (from_space_->HasAddress(obj)) {
mirror::Object* forward_address = GetForwardingAddressInFromSpace(obj);
// If the object has already been moved, return the new forward address.
- if (!to_space_->HasAddress(forward_address)) {
+ if (forward_address == nullptr) {
// Otherwise, we need to move the object and add it to the markstack for processing.
size_t object_size = obj->SizeOf();
size_t dummy = 0;
- forward_address = to_space_->Alloc(self_, object_size, &dummy);
+ if (kEnableSimplePromo && reinterpret_cast<byte*>(obj) < last_gc_to_space_end_) {
+ // If it's allocated before the last GC (older), move (pseudo-promote) it to
+ // the non-moving space (as sort of an old generation.)
+ size_t bytes_promoted;
+ space::MallocSpace* non_moving_space = GetHeap()->GetNonMovingSpace();
+ forward_address = non_moving_space->Alloc(self_, object_size, &bytes_promoted);
+ if (forward_address == nullptr) {
+ // If out of space, fall back to the to-space.
+ forward_address = to_space_->Alloc(self_, object_size, &dummy);
+ } else {
+ GetHeap()->num_bytes_allocated_.fetch_add(bytes_promoted);
+ bytes_promoted_ += bytes_promoted;
+ // Mark forward_address on the live bit map.
+ accounting::SpaceBitmap* live_bitmap = non_moving_space->GetLiveBitmap();
+ DCHECK(live_bitmap != nullptr);
+ DCHECK(!live_bitmap->Test(forward_address));
+ live_bitmap->Set(forward_address);
+ // Mark forward_address on the mark bit map.
+ accounting::SpaceBitmap* mark_bitmap = non_moving_space->GetMarkBitmap();
+ DCHECK(mark_bitmap != nullptr);
+ DCHECK(!mark_bitmap->Test(forward_address));
+ mark_bitmap->Set(forward_address);
+ }
+ DCHECK(forward_address != nullptr);
+ } else {
+ // If it's allocated after the last GC (younger), copy it to the to-space.
+ forward_address = to_space_->Alloc(self_, object_size, &dummy);
+ }
// Copy over the object and add it to the mark stack since we still need to update it's
// references.
memcpy(reinterpret_cast<void*>(forward_address), obj, object_size);
@@ -322,6 +371,9 @@
monitor_size_must_be_same_as_object);
obj->SetLockWord(LockWord::FromForwardingAddress(reinterpret_cast<size_t>(forward_address)));
MarkStackPush(forward_address);
+ } else {
+ DCHECK(to_space_->HasAddress(forward_address) ||
+ (kEnableSimplePromo && GetHeap()->GetNonMovingSpace()->HasAddress(forward_address)));
}
ret = forward_address;
// TODO: Do we need this if in the else statement?
@@ -535,7 +587,9 @@
if (from_space_->HasAddress(obj)) {
mirror::Object* forwarding_address = GetForwardingAddressInFromSpace(const_cast<Object*>(obj));
// If the object is forwarded then it MUST be marked.
- if (to_space_->HasAddress(forwarding_address)) {
+ DCHECK(forwarding_address == nullptr || to_space_->HasAddress(forwarding_address) ||
+ (kEnableSimplePromo && GetHeap()->GetNonMovingSpace()->HasAddress(forwarding_address)));
+ if (forwarding_address != nullptr) {
return forwarding_address;
}
// Must not be marked, return nullptr;
diff --git a/runtime/gc/collector/semi_space.h b/runtime/gc/collector/semi_space.h
index 0f0cae1..b0724f9 100644
--- a/runtime/gc/collector/semi_space.h
+++ b/runtime/gc/collector/semi_space.h
@@ -281,6 +281,15 @@
Thread* self_;
+ // Used for kEnableSimplePromo. The end/top of the bump pointer
+ // space at the end of the last collection.
+ byte* last_gc_to_space_end_;
+
+ // Used for kEnableSimplePromo. During a collection, keeps track of
+ // how many bytes of objects have been copied so far from the bump
+ // pointer space to the non-moving space.
+ uint64_t bytes_promoted_;
+
private:
DISALLOW_COPY_AND_ASSIGN(SemiSpace);
};