Add clamp growth limit
Clamp growth limit shrinks the space memmaps to the current growth
limit. This reduces virtual memory usage for apps with small heaps.
Bug: 18387825
Bug: 17131630
Change-Id: I4a8fdc335d2c40492e991708adabcc46299efb7d
diff --git a/runtime/gc/accounting/space_bitmap.h b/runtime/gc/accounting/space_bitmap.h
index e73166b..7bc83ef 100644
--- a/runtime/gc/accounting/space_bitmap.h
+++ b/runtime/gc/accounting/space_bitmap.h
@@ -160,6 +160,12 @@
return IndexToOffset<uint64_t>(Size() / sizeof(intptr_t));
}
+ void SetHeapSize(size_t bytes) {
+ // TODO: Un-map the end of the mem map.
+ bitmap_size_ = OffsetToIndex(bytes) * sizeof(intptr_t);
+ CHECK_EQ(HeapSize(), bytes);
+ }
+
uintptr_t HeapBegin() const {
return heap_begin_;
}
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 2575676..db287d3 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -2978,6 +2978,20 @@
}
}
+void Heap::ClampGrowthLimit() {
+ capacity_ = growth_limit_;
+ for (const auto& space : continuous_spaces_) {
+ if (space->IsMallocSpace()) {
+ gc::space::MallocSpace* malloc_space = space->AsMallocSpace();
+ malloc_space->ClampGrowthLimit();
+ }
+ }
+ // This space isn't added for performance reasons.
+ if (main_space_backup_.get() != nullptr) {
+ main_space_backup_->ClampGrowthLimit();
+ }
+}
+
void Heap::ClearGrowthLimit() {
growth_limit_ = capacity_;
for (const auto& space : continuous_spaces_) {
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index 1738124..fc61fc5 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -302,6 +302,10 @@
// implement dalvik.system.VMRuntime.clearGrowthLimit.
void ClearGrowthLimit();
+ // Make the current growth limit the new maximum capacity, unmaps pages at the end of spaces
+ // which will never be used. Used to implement dalvik.system.VMRuntime.clampGrowthLimit.
+ void ClampGrowthLimit();
+
// Target ideal heap utilization ratio, implements
// dalvik.system.VMRuntime.getTargetHeapUtilization.
double GetTargetHeapUtilization() const {
@@ -902,7 +906,7 @@
collector::GcType next_gc_type_;
// Maximum size that the heap can reach.
- const size_t capacity_;
+ size_t capacity_;
// The size the heap is limited to. This is initially smaller than capacity, but for largeHeap
// programs it is "cleared" making it the same as capacity.
diff --git a/runtime/gc/space/malloc_space.cc b/runtime/gc/space/malloc_space.cc
index 7905bb4..9bbbb3c 100644
--- a/runtime/gc/space/malloc_space.cc
+++ b/runtime/gc/space/malloc_space.cc
@@ -248,6 +248,16 @@
context->freed.bytes += space->FreeList(self, num_ptrs, ptrs);
}
+void MallocSpace::ClampGrowthLimit() {
+ size_t new_capacity = Capacity();
+ CHECK_LE(new_capacity, NonGrowthLimitCapacity());
+ GetLiveBitmap()->SetHeapSize(new_capacity);
+ GetMarkBitmap()->SetHeapSize(new_capacity);
+ GetMemMap()->SetSize(new_capacity);
+ limit_ = Begin() + new_capacity;
+ CHECK(temp_bitmap_.get() == nullptr);
+}
+
} // namespace space
} // namespace gc
} // namespace art
diff --git a/runtime/gc/space/malloc_space.h b/runtime/gc/space/malloc_space.h
index 2fbd5f0..06239e5 100644
--- a/runtime/gc/space/malloc_space.h
+++ b/runtime/gc/space/malloc_space.h
@@ -110,6 +110,10 @@
return GetMemMap()->Size();
}
+ // Change the non growth limit capacity by shrinking or expanding the map. Currently, only
+ // shrinking is supported.
+ void ClampGrowthLimit();
+
void Dump(std::ostream& os) const;
void SetGrowthLimit(size_t growth_limit);
diff --git a/runtime/mem_map.cc b/runtime/mem_map.cc
index 8303f84..a722813 100644
--- a/runtime/mem_map.cc
+++ b/runtime/mem_map.cc
@@ -665,6 +665,19 @@
maps_ = nullptr;
}
+void MemMap::SetSize(size_t new_size) {
+ if (new_size == base_size_) {
+ return;
+ }
+ CHECK_ALIGNED(new_size, kPageSize);
+ CHECK_EQ(base_size_, size_) << "Unsupported";
+ CHECK_LE(new_size, base_size_);
+ CHECK_EQ(munmap(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(BaseBegin()) + new_size),
+ base_size_ - new_size), 0) << new_size << " " << base_size_;
+ base_size_ = new_size;
+ size_ = new_size;
+}
+
std::ostream& operator<<(std::ostream& os, const MemMap& mem_map) {
os << StringPrintf("[MemMap: %p-%p prot=0x%x %s]",
mem_map.BaseBegin(), mem_map.BaseEnd(), mem_map.GetProtect(),
diff --git a/runtime/mem_map.h b/runtime/mem_map.h
index 9b003aa..dc337e0 100644
--- a/runtime/mem_map.h
+++ b/runtime/mem_map.h
@@ -107,6 +107,9 @@
return size_;
}
+ // Resize the mem-map by unmapping pages at the end. Currently only supports shrinking.
+ void SetSize(size_t new_size);
+
uint8_t* End() const {
return Begin() + Size();
}
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index f503b35..471aa9c 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -134,6 +134,10 @@
Runtime::Current()->GetHeap()->ClearGrowthLimit();
}
+static void VMRuntime_clampGrowthLimit(JNIEnv*, jobject) {
+ Runtime::Current()->GetHeap()->ClampGrowthLimit();
+}
+
static jboolean VMRuntime_isDebuggerActive(JNIEnv*, jobject) {
return Dbg::IsDebuggerActive();
}
@@ -577,6 +581,7 @@
static JNINativeMethod gMethods[] = {
NATIVE_METHOD(VMRuntime, addressOf, "!(Ljava/lang/Object;)J"),
NATIVE_METHOD(VMRuntime, bootClassPath, "()Ljava/lang/String;"),
+ NATIVE_METHOD(VMRuntime, clampGrowthLimit, "()V"),
NATIVE_METHOD(VMRuntime, classPath, "()Ljava/lang/String;"),
NATIVE_METHOD(VMRuntime, clearGrowthLimit, "()V"),
NATIVE_METHOD(VMRuntime, concurrentGC, "()V"),