Trim reference tables when we trim the heap
Before:
System server:
virtual shared shared private private
size RSS PSS clean dirty clean dirty # object
2200 300 229 0 80 0 220 77 /dev/ashmem/dalvik-indirect ref table (deleted)
Location:
1896 128 102 0 28 0 100 39 /dev/ashmem/dalvik-indirect ref table (deleted)
After:
virtual shared shared private private
size RSS PSS clean dirty clean dirty # object
System server:
2216 64 64 0 0 0 64 79 /dev/ashmem/dalvik-indirect ref table (deleted)
Location:
2120 48 48 0 0 0 48 67 /dev/ashmem/dalvik-indirect ref table (deleted)
No pause time regression measured in memalloc test.
(cherry picked from commit 84dc99d2fa67e5dff018685661cb2bff62132989)
Change-Id: I80d9bd3b98e888fa8f77d03df69f8479ed209986
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 0cceaa4..7b679ea 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -977,6 +977,22 @@
Trim();
}
+class TrimIndirectReferenceTableClosure : public Closure {
+ public:
+ explicit TrimIndirectReferenceTableClosure(Barrier* barrier) : barrier_(barrier) {
+ }
+ virtual void Run(Thread* thread) OVERRIDE NO_THREAD_SAFETY_ANALYSIS {
+ ATRACE_BEGIN("Trimming reference table");
+ thread->GetJniEnv()->locals.Trim();
+ ATRACE_END();
+ barrier_->Pass(Thread::Current());
+ }
+
+ private:
+ Barrier* const barrier_;
+};
+
+
void Heap::Trim() {
Thread* self = Thread::Current();
{
@@ -998,6 +1014,19 @@
WaitForGcToCompleteLocked(kGcCauseTrim, self);
collector_type_running_ = kCollectorTypeHeapTrim;
}
+ // Trim reference tables.
+ {
+ ScopedObjectAccess soa(self);
+ JavaVMExt* vm = soa.Vm();
+ // Trim globals indirect reference table.
+ vm->TrimGlobals();
+ // Trim locals indirect reference tables.
+ Barrier barrier(0);
+ TrimIndirectReferenceTableClosure closure(&barrier);
+ ScopedThreadStateChange tsc(self, kWaitingForCheckPointsToRun);
+ size_t barrier_count = Runtime::Current()->GetThreadList()->RunCheckpoint(&closure);
+ barrier.Increment(self, barrier_count);
+ }
uint64_t start_ns = NanoTime();
// Trim the managed spaces.
uint64_t total_alloc_space_allocated = 0;
diff --git a/runtime/indirect_reference_table.cc b/runtime/indirect_reference_table.cc
index 4d177a3..0d84a1e 100644
--- a/runtime/indirect_reference_table.cc
+++ b/runtime/indirect_reference_table.cc
@@ -162,13 +162,12 @@
DCHECK(table_ != NULL);
DCHECK_GE(segment_state_.parts.numHoles, prevState.parts.numHoles);
- int idx = ExtractIndex(iref);
-
if (GetIndirectRefKind(iref) == kHandleScopeOrInvalid &&
Thread::Current()->HandleScopeContains(reinterpret_cast<jobject>(iref))) {
LOG(WARNING) << "Attempt to remove local handle scope entry from IRT, ignoring";
return true;
}
+ const int idx = ExtractIndex(iref);
if (idx < bottomIndex) {
// Wrong segment.
LOG(WARNING) << "Attempt to remove index outside index area (" << idx
@@ -236,6 +235,13 @@
return true;
}
+void IndirectReferenceTable::Trim() {
+ const size_t top_index = Capacity();
+ auto* release_start = AlignUp(reinterpret_cast<uint8_t*>(&table_[top_index]), kPageSize);
+ uint8_t* release_end = table_mem_map_->End();
+ madvise(release_start, release_end - release_start, MADV_DONTNEED);
+}
+
void IndirectReferenceTable::VisitRoots(RootCallback* callback, void* arg, uint32_t tid,
RootType root_type) {
for (auto ref : *this) {
diff --git a/runtime/indirect_reference_table.h b/runtime/indirect_reference_table.h
index 168f9f2..fbd5714 100644
--- a/runtime/indirect_reference_table.h
+++ b/runtime/indirect_reference_table.h
@@ -331,6 +331,9 @@
return Offset(OFFSETOF_MEMBER(IndirectReferenceTable, segment_state_));
}
+ // Release pages past the end of the table that may have previously held references.
+ void Trim() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
private:
// Extract the table index from an indirect reference.
static uint32_t ExtractIndex(IndirectRef iref) {
diff --git a/runtime/java_vm_ext.cc b/runtime/java_vm_ext.cc
index a5abce6..5d04fac 100644
--- a/runtime/java_vm_ext.cc
+++ b/runtime/java_vm_ext.cc
@@ -756,6 +756,11 @@
}
}
+void JavaVMExt::TrimGlobals() {
+ WriterMutexLock mu(Thread::Current(), globals_lock_);
+ globals_.Trim();
+}
+
void JavaVMExt::VisitRoots(RootCallback* callback, void* arg) {
Thread* self = Thread::Current();
{
diff --git a/runtime/java_vm_ext.h b/runtime/java_vm_ext.h
index 2957ba3..749b9fb 100644
--- a/runtime/java_vm_ext.h
+++ b/runtime/java_vm_ext.h
@@ -131,6 +131,9 @@
return unchecked_functions_;
}
+ void TrimGlobals() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ LOCKS_EXCLUDED(globals_lock_);
+
private:
Runtime* const runtime_;