Simple heap trimming.

Change-Id: I8a94b637e64c6b5586db3c41b6e9230e7c8250c8
diff --git a/src/dalvik_system_VMRuntime.cc b/src/dalvik_system_VMRuntime.cc
index 76da622..feb7749 100644
--- a/src/dalvik_system_VMRuntime.cc
+++ b/src/dalvik_system_VMRuntime.cc
@@ -19,7 +19,9 @@
 #include "jni_internal.h"
 #include "object.h"
 #include "object_utils.h"
+#include "space.h"
 #include "thread.h"
+#include "thread_list.h"
 
 #include "JniConstants.h" // Last to avoid problems with LOG redefinition.
 #include "toStringArray.h"
@@ -131,6 +133,13 @@
   }
 }
 
+void VMRuntime_trimHeap(JNIEnv* env, jobject) {
+  ScopedThreadListLock thread_list_lock;
+  uint64_t start_ns = NanoTime();
+  Heap::GetAllocSpace()->Trim();
+  VLOG(gc) << "VMRuntime_trimHeap took " << PrettyDuration(NanoTime() - start_ns);
+}
+
 JNINativeMethod gMethods[] = {
   NATIVE_METHOD(VMRuntime, addressOf, "(Ljava/lang/Object;)J"),
   NATIVE_METHOD(VMRuntime, bootClassPath, "()Ljava/lang/String;"),
@@ -144,6 +153,7 @@
   NATIVE_METHOD(VMRuntime, properties, "()[Ljava/lang/String;"),
   NATIVE_METHOD(VMRuntime, setTargetSdkVersion, "(I)V"),
   NATIVE_METHOD(VMRuntime, startJitCompilation, "()V"),
+  NATIVE_METHOD(VMRuntime, trimHeap, "()V"),
   NATIVE_METHOD(VMRuntime, vmVersion, "()Ljava/lang/String;"),
 };
 
diff --git a/src/heap.cc b/src/heap.cc
index 2451857..2b5be9c 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -522,9 +522,10 @@
   thread_list->ResumeAll();
 
   EnqueueClearedReferences(&cleared_references);
+  RequestHeapTrim();
 
   uint64_t duration_ns = t1 - t0;
-  bool gc_was_particularly_slow = duration_ns > MsToNs(100); // TODO: crank this down for concurrent.
+  bool gc_was_particularly_slow = duration_ns > MsToNs(50); // TODO: crank this down for concurrent.
   if (VLOG_IS_ON(gc) || gc_was_particularly_slow) {
     // TODO: somehow make the specific GC implementation (here MarkSweep) responsible for logging.
     size_t bytes_freed = initial_size - num_bytes_allocated_;
@@ -716,4 +717,24 @@
   }
 }
 
+void Heap::RequestHeapTrim() {
+  // We don't have a good measure of how worthwhile a trim might be. We can't use the live bitmap
+  // because that only marks object heads, so a large array looks like lots of empty space. We
+  // don't just call dlmalloc all the time, because the cost of an _attempted_ trim is proportional
+  // to utilization (which is probably inversely proportional to how much benefit we can expect).
+  // We could try mincore(2) but that's only a measure of how many pages we haven't given away,
+  // not how much use we're making of those pages.
+  float utilization = static_cast<float>(num_bytes_allocated_) / alloc_space_->Size();
+  if (utilization > 0.75f) {
+    // Don't bother trimming the heap if it's more than 75% utilized.
+    // (This percentage was picked arbitrarily.)
+    return;
+  }
+  JNIEnv* env = Thread::Current()->GetJniEnv();
+  static jclass Daemons_class = CacheClass(env, "java/lang/Daemons");
+  static jmethodID Daemons_requestHeapTrim = env->GetStaticMethodID(Daemons_class, "requestHeapTrim", "()V");
+  env->CallStaticVoidMethod(Daemons_class, Daemons_requestHeapTrim);
+  CHECK(!env->ExceptionCheck());
+}
+
 }  // namespace art
diff --git a/src/heap.h b/src/heap.h
index ebb1c85..58d7924 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -218,6 +218,8 @@
   // Pushes a list of cleared references out to the managed heap.
   static void EnqueueClearedReferences(Object** cleared_references);
 
+  static void RequestHeapTrim();
+
   static void RecordAllocationLocked(AllocSpace* space, const Object* object);
   static void RecordImageAllocations(Space* space);
 
diff --git a/src/runtime.cc b/src/runtime.cc
index 306bb87..60e875b 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -553,6 +553,7 @@
   jmethodID mid = env->GetStaticMethodID(c.get(), "start", "()V");
   CHECK(mid != NULL);
   env->CallStaticVoidMethod(c.get(), mid);
+  CHECK(!env->ExceptionCheck());
 
   VLOG(startup) << "Runtime::StartDaemonThreads exiting";
 }
diff --git a/src/signal_catcher.h b/src/signal_catcher.h
index 8554531..f237b12 100644
--- a/src/signal_catcher.h
+++ b/src/signal_catcher.h
@@ -25,7 +25,7 @@
 class Thread;
 
 /*
- * A thread that catches signals and does something useful. For
+ * A daemon thread that catches signals and does something useful. For
  * example, when a SIGQUIT (Ctrl-\) arrives, we suspend and dump the
  * status of all threads.
  */