Allocate a contiguous region of virtual memory to be subdivided among
the various heaps managed by the garbage collector.  Because we cannot
tell how far the break has been advanced by morecore, we over allocate
virtual memory and grain each heap on a multiple of the maximum heap
size.  If we could reckon the position of the break, we could allocate
just as many pages as required.  This requires exporting more state
from mspace.c, a refinement I will reserve for a future change list.
diff --git a/vm/alloc/Heap.c b/vm/alloc/Heap.c
index d23e2a6..8178489 100644
--- a/vm/alloc/Heap.c
+++ b/vm/alloc/Heap.c
@@ -106,8 +106,7 @@
     return true;
 
 fail:
-    gDvm.gcHeap = NULL;
-    dvmHeapSourceShutdown(gcHeap);
+    dvmHeapSourceShutdown(&gcHeap);
     return false;
 }
 
@@ -123,33 +122,28 @@
 {
 //TODO: make sure we're locked
     if (gDvm.gcHeap != NULL) {
-        GcHeap *gcHeap;
-
-        gcHeap = gDvm.gcHeap;
-        gDvm.gcHeap = NULL;
-
         /* Tables are allocated on the native heap;
          * they need to be cleaned up explicitly.
          * The process may stick around, so we don't
          * want to leak any native memory.
          */
-        dvmHeapFreeHeapRefTable(&gcHeap->nonCollectableRefs);
+        dvmHeapFreeHeapRefTable(&gDvm.gcHeap->nonCollectableRefs);
 
-        dvmHeapFreeLargeTable(gcHeap->finalizableRefs);
-        gcHeap->finalizableRefs = NULL;
+        dvmHeapFreeLargeTable(gDvm.gcHeap->finalizableRefs);
+        gDvm.gcHeap->finalizableRefs = NULL;
 
-        dvmHeapFreeLargeTable(gcHeap->pendingFinalizationRefs);
-        gcHeap->pendingFinalizationRefs = NULL;
+        dvmHeapFreeLargeTable(gDvm.gcHeap->pendingFinalizationRefs);
+        gDvm.gcHeap->pendingFinalizationRefs = NULL;
 
-        dvmHeapFreeLargeTable(gcHeap->referenceOperations);
-        gcHeap->referenceOperations = NULL;
+        dvmHeapFreeLargeTable(gDvm.gcHeap->referenceOperations);
+        gDvm.gcHeap->referenceOperations = NULL;
 
         /* Destroy the heap.  Any outstanding pointers
          * will point to unmapped memory (unless/until
-         * someone else maps it).  This frees gcHeap
+         * someone else maps it).  This frees gDvm.gcHeap
          * as a side-effect.
          */
-        dvmHeapSourceShutdown(gcHeap);
+        dvmHeapSourceShutdown(&gDvm.gcHeap);
     }
 }
 
diff --git a/vm/alloc/HeapSource.c b/vm/alloc/HeapSource.c
index b0adea9..209c72d 100644
--- a/vm/alloc/HeapSource.c
+++ b/vm/alloc/HeapSource.c
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <cutils/ashmem.h>
 #include <cutils/mspace.h>
 #include <limits.h>     // for INT_MAX
 #include <sys/mman.h>
@@ -165,6 +166,16 @@
     /* True if zygote mode was active when the HeapSource was created.
      */
     bool sawZygote;
+
+    /*
+     * The base address of the virtual memory reservation.
+     */
+    char *heapBase;
+
+    /*
+     * The length in bytes of the virtual memory reservation.
+     */
+    size_t heapLength;
 };
 
 #define hs2heap(hs_) (&((hs_)->heaps[0]))
@@ -275,17 +286,9 @@
 static HeapSource *gHs = NULL;
 
 static mspace
-createMspace(size_t startSize, size_t absoluteMaxSize, size_t id)
+createMspace(void *base, size_t startSize, size_t absoluteMaxSize)
 {
     mspace msp;
-    char name[PATH_MAX];
-
-    /* If two ashmem regions have the same name, only one gets
-     * the name when looking at the maps.
-     */
-    snprintf(name, sizeof(name)-1, "dalvik-heap%s/%zd",
-        gDvm.zygote ? "/zygote" : "", id);
-    name[sizeof(name)-1] = '\0';
 
     /* Create an unlocked dlmalloc mspace to use as
      * a small-object heap source.
@@ -297,8 +300,8 @@
      */
     LOGV_HEAP("Creating VM heap of size %u\n", startSize);
     errno = 0;
-    msp = create_contiguous_mspace_with_name(startSize/2,
-            absoluteMaxSize, /*locked=*/false, name);
+    msp = create_contiguous_mspace_with_base(startSize/2,
+            absoluteMaxSize, /*locked=*/false, base);
     if (msp != NULL) {
         /* Don't let the heap grow past the starting size without
          * our intervention.
@@ -319,6 +322,7 @@
 addNewHeap(HeapSource *hs, mspace msp, size_t mspAbsoluteMaxSize)
 {
     Heap heap;
+    void *base;
 
     if (hs->numHeaps >= HEAP_SOURCE_MAX_HEAP_COUNT) {
         LOGE("Attempt to create too many heaps (%zd >= %zd)\n",
@@ -343,8 +347,8 @@
             return false;
         }
         heap.absoluteMaxSize = hs->absoluteMaxSize - overhead;
-        heap.msp = createMspace(HEAP_MIN_FREE, heap.absoluteMaxSize,
-                hs->numHeaps);
+        base = hs->heapBase + ALIGN_UP_TO_PAGE_SIZE(hs->absoluteMaxSize);
+        heap.msp = createMspace(base, HEAP_MIN_FREE, heap.absoluteMaxSize);
         if (heap.msp == NULL) {
             return false;
         }
@@ -355,7 +359,7 @@
                            "objects"))
     {
         LOGE_HEAP("Can't create objectBitmap\n");
-        goto fail;
+        return false;
     }
 
     /* Don't let the soon-to-be-old heap grow any further.
@@ -373,12 +377,6 @@
     hs->numHeaps++;
 
     return true;
-
-fail:
-    if (msp == NULL) {
-        destroy_contiguous_mspace(heap.msp);
-    }
-    return false;
 }
 
 /*
@@ -393,6 +391,9 @@
     HeapSource *hs;
     Heap *heap;
     mspace msp;
+    size_t length;
+    void *base;
+    int fd, ret;
 
     assert(gHs == NULL);
 
@@ -402,12 +403,31 @@
         return NULL;
     }
 
+    /*
+     * Allocate a contiguous region of virtual memory to subdivided
+     * among the heaps managed by the garbage collector.
+     */
+    length = ALIGN_UP_TO_PAGE_SIZE(absoluteMaxSize);
+    length *= HEAP_SOURCE_MAX_HEAP_COUNT;
+    fd = ashmem_create_region("the-java-heap", length);
+    if (fd == -1) {
+        return NULL;
+    }
+    base = mmap(NULL, length, PROT_NONE, MAP_PRIVATE, fd, 0);
+    if (base == MAP_FAILED) {
+        return NULL;
+    }
+    ret = close(fd);
+    if (ret == -1) {
+        goto fail;
+    }
+
     /* Create an unlocked dlmalloc mspace to use as
      * the small object heap source.
      */
-    msp = createMspace(startSize, absoluteMaxSize, 0);
+    msp = createMspace(base, startSize, absoluteMaxSize);
     if (msp == NULL) {
-        return false;
+        goto fail;
     }
 
     /* Allocate a descriptor from the heap we just created.
@@ -434,6 +454,8 @@
     hs->softLimit = INT_MAX;    // no soft limit at first
     hs->numHeaps = 0;
     hs->sawZygote = gDvm.zygote;
+    hs->heapBase = base;
+    hs->heapLength = length;
     if (!addNewHeap(hs, msp, absoluteMaxSize)) {
         LOGE_HEAP("Can't add initial heap\n");
         goto fail;
@@ -448,7 +470,7 @@
     return gcHeap;
 
 fail:
-    destroy_contiguous_mspace(msp);
+    munmap(base, length);
     return NULL;
 }
 
@@ -480,33 +502,31 @@
 }
 
 /*
- * Tears down the heap source and frees any resources associated with it.
+ * Tears down the entire GcHeap structure and all of the substructures
+ * attached to it.  This call has the side effect of setting the given
+ * gcHeap pointer and gHs to NULL.
  */
 void
-dvmHeapSourceShutdown(GcHeap *gcHeap)
+dvmHeapSourceShutdown(GcHeap **gcHeap)
 {
-    if (gcHeap != NULL && gcHeap->heapSource != NULL) {
+    if (*gcHeap != NULL && (*gcHeap)->heapSource != NULL) {
         HeapSource *hs;
-        size_t numHeaps;
         size_t i;
 
-        hs = gcHeap->heapSource;
-        gHs = NULL;
+        hs = (*gcHeap)->heapSource;
 
-        /* Cache numHeaps because hs will be invalid after the last
-         * heap is freed.
-         */
-        numHeaps = hs->numHeaps;
+        assert((char *)*gcHeap >= hs->heapBase);
+        assert((char *)*gcHeap < hs->heapBase + hs->heapLength);
 
-        for (i = 0; i < numHeaps; i++) {
+        for (i = 0; i < hs->numHeaps; i++) {
             Heap *heap = &hs->heaps[i];
 
             dvmHeapBitmapDelete(&heap->objectBitmap);
-            destroy_contiguous_mspace(heap->msp);
         }
-        /* The last heap is the original one, which contains the
-         * HeapSource object itself.
-         */
+
+        munmap(hs->heapBase, hs->heapLength);
+        gHs = NULL;
+        *gcHeap = NULL;
     }
 }
 
diff --git a/vm/alloc/HeapSource.h b/vm/alloc/HeapSource.h
index 43113cb..51b0a90 100644
--- a/vm/alloc/HeapSource.h
+++ b/vm/alloc/HeapSource.h
@@ -44,7 +44,7 @@
 /*
  * Tears down the heap source and frees any resources associated with it.
  */
-void dvmHeapSourceShutdown(GcHeap *gcHeap);
+void dvmHeapSourceShutdown(GcHeap **gcHeap);
 
 /*
  * Writes shallow copies of the currently-used bitmaps into outBitmaps,