Home | History | Annotate | Download | only in alloc
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <cutils/mspace.h>
     18 #include <stdint.h>     // for SIZE_MAX
     19 #include <sys/mman.h>
     20 #include <errno.h>
     21 
     22 #include "Dalvik.h"
     23 #include "alloc/Heap.h"
     24 #include "alloc/HeapInternal.h"
     25 #include "alloc/HeapSource.h"
     26 #include "alloc/HeapBitmap.h"
     27 
     28 // TODO: find a real header file for these.
     29 extern int dlmalloc_trim(size_t);
     30 extern void dlmalloc_walk_free_pages(void(*)(void*, void*, void*), void*);
     31 
     32 static void snapIdealFootprint(void);
     33 static void setIdealFootprint(size_t max);
     34 
     35 #define ALIGN_UP_TO_PAGE_SIZE(p) \
     36     (((size_t)(p) + (SYSTEM_PAGE_SIZE - 1)) & ~(SYSTEM_PAGE_SIZE - 1))
     37 #define ALIGN_DOWN_TO_PAGE_SIZE(p) \
     38     ((size_t)(p) & ~(SYSTEM_PAGE_SIZE - 1))
     39 
     40 #define HEAP_UTILIZATION_MAX        1024
     41 #define DEFAULT_HEAP_UTILIZATION    512     // Range 1..HEAP_UTILIZATION_MAX
     42 #define HEAP_IDEAL_FREE             (2 * 1024 * 1024)
     43 #define HEAP_MIN_FREE               (HEAP_IDEAL_FREE / 4)
     44 
     45 /* Start a concurrent collection when free memory falls under this
     46  * many bytes.
     47  */
     48 #define CONCURRENT_START (128 << 10)
     49 
     50 /* The next GC will not be concurrent when free memory after a GC is
     51  * under this many bytes.
     52  */
     53 #define CONCURRENT_MIN_FREE (CONCURRENT_START + (128 << 10))
     54 
     55 #define HS_BOILERPLATE() \
     56     do { \
     57         assert(gDvm.gcHeap != NULL); \
     58         assert(gDvm.gcHeap->heapSource != NULL); \
     59         assert(gHs == gDvm.gcHeap->heapSource); \
     60     } while (0)
     61 
     62 #define DEBUG_HEAP_SOURCE 0
     63 #if DEBUG_HEAP_SOURCE
     64 #define HSTRACE(...)  LOG(LOG_INFO, LOG_TAG "-hs", __VA_ARGS__)
     65 #else
     66 #define HSTRACE(...)  /**/
     67 #endif
     68 
     69 /*
     70 =======================================================
     71 =======================================================
     72 =======================================================
     73 
     74 How will this be used?
     75 allocating/freeing: Heap.c just wants to say "alloc(n)" and get a ptr
     76     - if allocating in large doesn't work, try allocating from small
     77 Heap.c will use HeapSource.h; HeapSource.c will do the right thing
     78     between small and large
     79     - some operations should be abstracted; put in a structure
     80 
     81 How do we manage the size trade-offs?
     82 - keep mspace max footprint clamped to actual footprint
     83 - if small-alloc returns null, adjust large vs. small ratio
     84     - give small all available slack and retry
     85     - success or fail, snap back to actual footprint and give rest to large
     86 
     87 managed as "small actual" + "large actual" + "delta to allowed total footprint"
     88 - when allocating from one source or the other, give the delta to the
     89     active source, but snap back afterwards
     90 - that may not work so great for a gc heap, because small will always consume.
     91     - but we need to use the memory, and the current max is the amount we
     92       need to fill before a GC.
     93 
     94 Find a way to permanently steal pages from the middle of the heap
     95     - segment tricks?
     96 
     97 Allocate String and char[] in a separate heap?
     98 
     99 Maybe avoid growing small heap, even if there's slack?  Look at
    100 live ratio of small heap after a gc; scale it based on that.
    101 
    102 =======================================================
    103 =======================================================
    104 =======================================================
    105 */
    106 
    107 typedef struct {
    108     /* The mspace to allocate from.
    109      */
    110     mspace msp;
    111 
    112     /* The largest size that this heap is allowed to grow to.
    113      */
    114     size_t absoluteMaxSize;
    115 
    116     /* Number of bytes allocated from this mspace for objects,
    117      * including any overhead.  This value is NOT exact, and
    118      * should only be used as an input for certain heuristics.
    119      */
    120     size_t bytesAllocated;
    121 
    122     /* Number of bytes allocated from this mspace at which a
    123      * concurrent garbage collection will be started.
    124      */
    125     size_t concurrentStartBytes;
    126 
    127     /* Number of objects currently allocated from this mspace.
    128      */
    129     size_t objectsAllocated;
    130 
    131     /*
    132      * The lowest address of this heap, inclusive.
    133      */
    134     char *base;
    135 
    136     /*
    137      * The highest address of this heap, exclusive.
    138      */
    139     char *limit;
    140 } Heap;
    141 
    142 struct HeapSource {
    143     /* Target ideal heap utilization ratio; range 1..HEAP_UTILIZATION_MAX
    144      */
    145     size_t targetUtilization;
    146 
    147     /* Requested minimum heap size, or zero if there is no minimum.
    148      */
    149     size_t minimumSize;
    150 
    151     /* The starting heap size.
    152      */
    153     size_t startSize;
    154 
    155     /* The largest that the heap source as a whole is allowed to grow.
    156      */
    157     size_t absoluteMaxSize;
    158 
    159     /* The desired max size of the heap source as a whole.
    160      */
    161     size_t idealSize;
    162 
    163     /* The maximum number of bytes allowed to be allocated from the
    164      * active heap before a GC is forced.  This is used to "shrink" the
    165      * heap in lieu of actual compaction.
    166      */
    167     size_t softLimit;
    168 
    169     /* The heaps; heaps[0] is always the active heap,
    170      * which new objects should be allocated from.
    171      */
    172     Heap heaps[HEAP_SOURCE_MAX_HEAP_COUNT];
    173 
    174     /* The current number of heaps.
    175      */
    176     size_t numHeaps;
    177 
    178     /* External allocation count.
    179      */
    180     size_t externalBytesAllocated;
    181 
    182     /* The maximum number of external bytes that may be allocated.
    183      */
    184     size_t externalLimit;
    185 
    186     /* True if zygote mode was active when the HeapSource was created.
    187      */
    188     bool sawZygote;
    189 
    190     /*
    191      * The base address of the virtual memory reservation.
    192      */
    193     char *heapBase;
    194 
    195     /*
    196      * The length in bytes of the virtual memory reservation.
    197      */
    198     size_t heapLength;
    199 
    200     /*
    201      * The live object bitmap.
    202      */
    203     HeapBitmap liveBits;
    204 
    205     /*
    206      * The mark bitmap.
    207      */
    208     HeapBitmap markBits;
    209 
    210     /*
    211      * State for the GC daemon.
    212      */
    213     bool hasGcThread;
    214     pthread_t gcThread;
    215     bool gcThreadShutdown;
    216     pthread_mutex_t gcThreadMutex;
    217     pthread_cond_t gcThreadCond;
    218 };
    219 
    220 #define hs2heap(hs_) (&((hs_)->heaps[0]))
    221 
    222 /*
    223  * Returns true iff a soft limit is in effect for the active heap.
    224  */
    225 static inline bool
    226 softLimited(const HeapSource *hs)
    227 {
    228     /* softLimit will be either SIZE_MAX or the limit for the
    229      * active mspace.  idealSize can be greater than softLimit
    230      * if there is more than one heap.  If there is only one
    231      * heap, a non-SIZE_MAX softLimit should always be the same
    232      * as idealSize.
    233      */
    234     return hs->softLimit <= hs->idealSize;
    235 }
    236 
    237 /*
    238  * Returns approximately the maximum number of bytes allowed to be
    239  * allocated from the active heap before a GC is forced.
    240  */
    241 static size_t
    242 getAllocLimit(const HeapSource *hs)
    243 {
    244     if (softLimited(hs)) {
    245         return hs->softLimit;
    246     } else {
    247         return mspace_max_allowed_footprint(hs2heap(hs)->msp);
    248     }
    249 }
    250 
    251 /*
    252  * Returns the current footprint of all heaps.  If includeActive
    253  * is false, don't count the heap at index 0.
    254  */
    255 static inline size_t
    256 oldHeapOverhead(const HeapSource *hs, bool includeActive)
    257 {
    258     size_t footprint = 0;
    259     size_t i;
    260 
    261     if (includeActive) {
    262         i = 0;
    263     } else {
    264         i = 1;
    265     }
    266     for (/* i = i */; i < hs->numHeaps; i++) {
    267 //TODO: include size of bitmaps?  If so, don't use bitsLen, listen to .max
    268         footprint += mspace_footprint(hs->heaps[i].msp);
    269     }
    270     return footprint;
    271 }
    272 
    273 /*
    274  * Returns the heap that <ptr> could have come from, or NULL
    275  * if it could not have come from any heap.
    276  */
    277 static inline Heap *
    278 ptr2heap(const HeapSource *hs, const void *ptr)
    279 {
    280     const size_t numHeaps = hs->numHeaps;
    281     size_t i;
    282 
    283 //TODO: unroll this to HEAP_SOURCE_MAX_HEAP_COUNT
    284     if (ptr != NULL) {
    285         for (i = 0; i < numHeaps; i++) {
    286             const Heap *const heap = &hs->heaps[i];
    287 
    288             if ((const char *)ptr >= heap->base && (const char *)ptr < heap->limit) {
    289                 return (Heap *)heap;
    290             }
    291         }
    292     }
    293     return NULL;
    294 }
    295 
    296 /*
    297  * Functions to update heapSource->bytesAllocated when an object
    298  * is allocated or freed.  mspace_usable_size() will give
    299  * us a much more accurate picture of heap utilization than
    300  * the requested byte sizes would.
    301  *
    302  * These aren't exact, and should not be treated as such.
    303  */
    304 static void countAllocation(Heap *heap, const void *ptr, bool isObj)
    305 {
    306     HeapSource *hs;
    307 
    308     assert(heap->bytesAllocated < mspace_footprint(heap->msp));
    309 
    310     heap->bytesAllocated += mspace_usable_size(heap->msp, ptr) +
    311             HEAP_SOURCE_CHUNK_OVERHEAD;
    312     if (isObj) {
    313         heap->objectsAllocated++;
    314         hs = gDvm.gcHeap->heapSource;
    315         dvmHeapBitmapSetObjectBit(&hs->liveBits, ptr);
    316     }
    317 
    318     assert(heap->bytesAllocated < mspace_footprint(heap->msp));
    319 }
    320 
    321 static void countFree(Heap *heap, const void *ptr, size_t *numBytes)
    322 {
    323     HeapSource *hs;
    324     size_t delta;
    325 
    326     delta = mspace_usable_size(heap->msp, ptr) + HEAP_SOURCE_CHUNK_OVERHEAD;
    327     assert(delta > 0);
    328     if (delta < heap->bytesAllocated) {
    329         heap->bytesAllocated -= delta;
    330     } else {
    331         heap->bytesAllocated = 0;
    332     }
    333     hs = gDvm.gcHeap->heapSource;
    334     dvmHeapBitmapClearObjectBit(&hs->liveBits, ptr);
    335     if (heap->objectsAllocated > 0) {
    336         heap->objectsAllocated--;
    337     }
    338     *numBytes += delta;
    339 }
    340 
    341 static HeapSource *gHs = NULL;
    342 
    343 static mspace
    344 createMspace(void *base, size_t startSize, size_t absoluteMaxSize)
    345 {
    346     mspace msp;
    347 
    348     /* Create an unlocked dlmalloc mspace to use as
    349      * a small-object heap source.
    350      *
    351      * We start off reserving heapSizeStart/2 bytes but
    352      * letting the heap grow to heapSizeStart.  This saves
    353      * memory in the case where a process uses even less
    354      * than the starting size.
    355      */
    356     LOGV_HEAP("Creating VM heap of size %u\n", startSize);
    357     errno = 0;
    358     msp = create_contiguous_mspace_with_base(startSize/2,
    359             absoluteMaxSize, /*locked=*/false, base);
    360     if (msp != NULL) {
    361         /* Don't let the heap grow past the starting size without
    362          * our intervention.
    363          */
    364         mspace_set_max_allowed_footprint(msp, startSize);
    365     } else {
    366         /* There's no guarantee that errno has meaning when the call
    367          * fails, but it often does.
    368          */
    369         LOGE_HEAP("Can't create VM heap of size (%u,%u): %s\n",
    370             startSize/2, absoluteMaxSize, strerror(errno));
    371     }
    372 
    373     return msp;
    374 }
    375 
    376 static bool
    377 addNewHeap(HeapSource *hs, mspace msp, size_t mspAbsoluteMaxSize)
    378 {
    379     Heap heap;
    380 
    381     if (hs->numHeaps >= HEAP_SOURCE_MAX_HEAP_COUNT) {
    382         LOGE("Attempt to create too many heaps (%zd >= %zd)\n",
    383                 hs->numHeaps, HEAP_SOURCE_MAX_HEAP_COUNT);
    384         dvmAbort();
    385         return false;
    386     }
    387 
    388     memset(&heap, 0, sizeof(heap));
    389 
    390     if (msp != NULL) {
    391         heap.msp = msp;
    392         heap.absoluteMaxSize = mspAbsoluteMaxSize;
    393         heap.concurrentStartBytes = SIZE_MAX;
    394         heap.base = hs->heapBase;
    395         heap.limit = hs->heapBase + heap.absoluteMaxSize;
    396     } else {
    397         void *sbrk0 = contiguous_mspace_sbrk0(hs->heaps[0].msp);
    398         char *base = (char *)ALIGN_UP_TO_PAGE_SIZE(sbrk0);
    399         size_t overhead = base - hs->heaps[0].base;
    400 
    401         assert(((size_t)hs->heaps[0].base & (SYSTEM_PAGE_SIZE - 1)) == 0);
    402         if (overhead + HEAP_MIN_FREE >= hs->absoluteMaxSize) {
    403             LOGE_HEAP("No room to create any more heaps "
    404                     "(%zd overhead, %zd max)\n",
    405                     overhead, hs->absoluteMaxSize);
    406             return false;
    407         }
    408         hs->heaps[0].absoluteMaxSize = overhead;
    409         hs->heaps[0].limit = base;
    410         heap.absoluteMaxSize = hs->absoluteMaxSize - overhead;
    411         heap.msp = createMspace(base, HEAP_MIN_FREE, heap.absoluteMaxSize);
    412         heap.concurrentStartBytes = HEAP_MIN_FREE - CONCURRENT_START;
    413         heap.base = base;
    414         heap.limit = heap.base + heap.absoluteMaxSize;
    415         if (heap.msp == NULL) {
    416             return false;
    417         }
    418     }
    419 
    420     /* Don't let the soon-to-be-old heap grow any further.
    421      */
    422     if (hs->numHeaps > 0) {
    423         mspace msp = hs->heaps[0].msp;
    424         mspace_set_max_allowed_footprint(msp, mspace_footprint(msp));
    425     }
    426 
    427     /* Put the new heap in the list, at heaps[0].
    428      * Shift existing heaps down.
    429      */
    430     memmove(&hs->heaps[1], &hs->heaps[0], hs->numHeaps * sizeof(hs->heaps[0]));
    431     hs->heaps[0] = heap;
    432     hs->numHeaps++;
    433 
    434     return true;
    435 }
    436 
    437 /*
    438  * The garbage collection daemon.  Initiates a concurrent collection
    439  * when signaled.
    440  */
    441 static void *gcDaemonThread(void* arg)
    442 {
    443     dvmChangeStatus(NULL, THREAD_VMWAIT);
    444     dvmLockMutex(&gHs->gcThreadMutex);
    445     while (gHs->gcThreadShutdown != true) {
    446         dvmWaitCond(&gHs->gcThreadCond, &gHs->gcThreadMutex);
    447         dvmLockHeap();
    448         dvmChangeStatus(NULL, THREAD_RUNNING);
    449         dvmCollectGarbageInternal(false, GC_CONCURRENT);
    450         dvmChangeStatus(NULL, THREAD_VMWAIT);
    451         dvmUnlockHeap();
    452     }
    453     dvmChangeStatus(NULL, THREAD_RUNNING);
    454     return NULL;
    455 }
    456 
    457 static bool gcDaemonStartup(void)
    458 {
    459     dvmInitMutex(&gHs->gcThreadMutex);
    460     pthread_cond_init(&gHs->gcThreadCond, NULL);
    461     gHs->gcThreadShutdown = false;
    462     gHs->hasGcThread = dvmCreateInternalThread(&gHs->gcThread, "GC",
    463                                                gcDaemonThread, NULL);
    464     return gHs->hasGcThread;
    465 }
    466 
    467 static void gcDaemonShutdown(void)
    468 {
    469     if (gHs->hasGcThread) {
    470         dvmLockMutex(&gHs->gcThreadMutex);
    471         gHs->gcThreadShutdown = true;
    472         dvmSignalCond(&gHs->gcThreadCond);
    473         dvmUnlockMutex(&gHs->gcThreadMutex);
    474         pthread_join(gHs->gcThread, NULL);
    475     }
    476 }
    477 
    478 /*
    479  * Initializes the heap source; must be called before any other
    480  * dvmHeapSource*() functions.  Returns a GcHeap structure
    481  * allocated from the heap source.
    482  */
    483 GcHeap *
    484 dvmHeapSourceStartup(size_t startSize, size_t absoluteMaxSize)
    485 {
    486     GcHeap *gcHeap;
    487     HeapSource *hs;
    488     mspace msp;
    489     size_t length;
    490     void *base;
    491 
    492     assert(gHs == NULL);
    493 
    494     if (startSize > absoluteMaxSize) {
    495         LOGE("Bad heap parameters (start=%d, max=%d)\n",
    496            startSize, absoluteMaxSize);
    497         return NULL;
    498     }
    499 
    500     /*
    501      * Allocate a contiguous region of virtual memory to subdivided
    502      * among the heaps managed by the garbage collector.
    503      */
    504     length = ALIGN_UP_TO_PAGE_SIZE(absoluteMaxSize);
    505     base = dvmAllocRegion(length, PROT_NONE, "dalvik-heap");
    506     if (base == NULL) {
    507         return NULL;
    508     }
    509 
    510     /* Create an unlocked dlmalloc mspace to use as
    511      * the small object heap source.
    512      */
    513     msp = createMspace(base, startSize, absoluteMaxSize);
    514     if (msp == NULL) {
    515         goto fail;
    516     }
    517 
    518     /* Allocate a descriptor from the heap we just created.
    519      */
    520     gcHeap = mspace_malloc(msp, sizeof(*gcHeap));
    521     if (gcHeap == NULL) {
    522         LOGE_HEAP("Can't allocate heap descriptor\n");
    523         goto fail;
    524     }
    525     memset(gcHeap, 0, sizeof(*gcHeap));
    526 
    527     hs = mspace_malloc(msp, sizeof(*hs));
    528     if (hs == NULL) {
    529         LOGE_HEAP("Can't allocate heap source\n");
    530         goto fail;
    531     }
    532     memset(hs, 0, sizeof(*hs));
    533 
    534     hs->targetUtilization = DEFAULT_HEAP_UTILIZATION;
    535     hs->minimumSize = 0;
    536     hs->startSize = startSize;
    537     hs->absoluteMaxSize = absoluteMaxSize;
    538     hs->idealSize = startSize;
    539     hs->softLimit = SIZE_MAX;    // no soft limit at first
    540     hs->numHeaps = 0;
    541     hs->sawZygote = gDvm.zygote;
    542     hs->hasGcThread = false;
    543     hs->heapBase = base;
    544     hs->heapLength = length;
    545     if (!addNewHeap(hs, msp, absoluteMaxSize)) {
    546         LOGE_HEAP("Can't add initial heap\n");
    547         goto fail;
    548     }
    549     if (!dvmHeapBitmapInit(&hs->liveBits, base, length, "dalvik-bitmap-1")) {
    550         LOGE_HEAP("Can't create liveBits\n");
    551         goto fail;
    552     }
    553     if (!dvmHeapBitmapInit(&hs->markBits, base, length, "dalvik-bitmap-2")) {
    554         LOGE_HEAP("Can't create markBits\n");
    555         dvmHeapBitmapDelete(&hs->liveBits);
    556         goto fail;
    557     }
    558 
    559     gcHeap->markContext.bitmap = &hs->markBits;
    560     gcHeap->heapSource = hs;
    561 
    562     countAllocation(hs2heap(hs), gcHeap, false);
    563     countAllocation(hs2heap(hs), hs, false);
    564 
    565     gHs = hs;
    566     return gcHeap;
    567 
    568 fail:
    569     munmap(base, length);
    570     return NULL;
    571 }
    572 
    573 bool dvmHeapSourceStartupAfterZygote(void)
    574 {
    575     return gDvm.concurrentMarkSweep ? gcDaemonStartup() : true;
    576 }
    577 
    578 /*
    579  * This is called while in zygote mode, right before we fork() for the
    580  * first time.  We create a heap for all future zygote process allocations,
    581  * in an attempt to avoid touching pages in the zygote heap.  (This would
    582  * probably be unnecessary if we had a compacting GC -- the source of our
    583  * troubles is small allocations filling in the gaps from larger ones.)
    584  */
    585 bool
    586 dvmHeapSourceStartupBeforeFork()
    587 {
    588     HeapSource *hs = gHs; // use a local to avoid the implicit "volatile"
    589 
    590     HS_BOILERPLATE();
    591 
    592     assert(gDvm.zygote);
    593 
    594     if (!gDvm.newZygoteHeapAllocated) {
    595         /* Create a new heap for post-fork zygote allocations.  We only
    596          * try once, even if it fails.
    597          */
    598         LOGV("Splitting out new zygote heap\n");
    599         gDvm.newZygoteHeapAllocated = true;
    600         return addNewHeap(hs, NULL, 0);
    601     }
    602     return true;
    603 }
    604 
    605 void dvmHeapSourceThreadShutdown(void)
    606 {
    607     if (gDvm.gcHeap != NULL && gDvm.concurrentMarkSweep) {
    608         gcDaemonShutdown();
    609     }
    610 }
    611 
    612 /*
    613  * Tears down the entire GcHeap structure and all of the substructures
    614  * attached to it.  This call has the side effect of setting the given
    615  * gcHeap pointer and gHs to NULL.
    616  */
    617 void
    618 dvmHeapSourceShutdown(GcHeap **gcHeap)
    619 {
    620     if (*gcHeap != NULL && (*gcHeap)->heapSource != NULL) {
    621         HeapSource *hs;
    622 
    623         hs = (*gcHeap)->heapSource;
    624 
    625         assert((char *)*gcHeap >= hs->heapBase);
    626         assert((char *)*gcHeap < hs->heapBase + hs->heapLength);
    627 
    628         dvmHeapBitmapDelete(&hs->liveBits);
    629         dvmHeapBitmapDelete(&hs->markBits);
    630 
    631         munmap(hs->heapBase, hs->heapLength);
    632         gHs = NULL;
    633         *gcHeap = NULL;
    634     }
    635 }
    636 
    637 /*
    638  * Gets the begining of the allocation for the HeapSource.
    639  */
    640 void *dvmHeapSourceGetBase(void)
    641 {
    642     return gHs->heapBase;
    643 }
    644 
    645 /*
    646  * Returns the requested value. If the per-heap stats are requested, fill
    647  * them as well.
    648  *
    649  * Caller must hold the heap lock.
    650  */
    651 size_t
    652 dvmHeapSourceGetValue(enum HeapSourceValueSpec spec, size_t perHeapStats[],
    653                       size_t arrayLen)
    654 {
    655     HeapSource *hs = gHs;
    656     size_t value = 0;
    657     size_t total = 0;
    658     size_t i;
    659 
    660     HS_BOILERPLATE();
    661 
    662     switch (spec) {
    663     case HS_EXTERNAL_BYTES_ALLOCATED:
    664         return hs->externalBytesAllocated;
    665     case HS_EXTERNAL_LIMIT:
    666         return hs->externalLimit;
    667     default:
    668         // look at all heaps.
    669         ;
    670     }
    671 
    672     assert(arrayLen >= hs->numHeaps || perHeapStats == NULL);
    673     for (i = 0; i < hs->numHeaps; i++) {
    674         Heap *const heap = &hs->heaps[i];
    675 
    676         switch (spec) {
    677         case HS_FOOTPRINT:
    678             value = mspace_footprint(heap->msp);
    679             break;
    680         case HS_ALLOWED_FOOTPRINT:
    681             value = mspace_max_allowed_footprint(heap->msp);
    682             break;
    683         case HS_BYTES_ALLOCATED:
    684             value = heap->bytesAllocated;
    685             break;
    686         case HS_OBJECTS_ALLOCATED:
    687             value = heap->objectsAllocated;
    688             break;
    689         default:
    690             // quiet gcc
    691             break;
    692         }
    693         if (perHeapStats) {
    694             perHeapStats[i] = value;
    695         }
    696         total += value;
    697     }
    698     return total;
    699 }
    700 
    701 static void aliasBitmap(HeapBitmap *dst, HeapBitmap *src,
    702                         uintptr_t base, uintptr_t max) {
    703     size_t offset;
    704 
    705     dst->base = base;
    706     dst->max = max;
    707     dst->bitsLen = HB_OFFSET_TO_BYTE_INDEX(max - base) + sizeof(dst->bits);
    708     /* The exclusive limit from bitsLen is greater than the inclusive max. */
    709     assert(base + HB_MAX_OFFSET(dst) > max);
    710     /* The exclusive limit is at most one word of bits beyond max. */
    711     assert((base + HB_MAX_OFFSET(dst)) - max <=
    712            HB_OBJECT_ALIGNMENT * HB_BITS_PER_WORD);
    713     dst->allocLen = dst->bitsLen;
    714     offset = base - src->base;
    715     assert(HB_OFFSET_TO_MASK(offset) == 1 << 31);
    716     dst->bits = &src->bits[HB_OFFSET_TO_INDEX(offset)];
    717 }
    718 
    719 /*
    720  * Initializes a vector of object and mark bits to the object and mark
    721  * bits of each heap.  The bits are aliased to the heapsource
    722  * object and mark bitmaps.  This routine is used by the sweep code
    723  * which needs to free each object in the correct heap.
    724  */
    725 void dvmHeapSourceGetObjectBitmaps(HeapBitmap liveBits[], HeapBitmap markBits[],
    726                                    size_t numHeaps)
    727 {
    728     HeapSource *hs = gHs;
    729     uintptr_t base, max;
    730     size_t i;
    731 
    732     HS_BOILERPLATE();
    733 
    734     assert(numHeaps == hs->numHeaps);
    735     for (i = 0; i < hs->numHeaps; ++i) {
    736         base = (uintptr_t)hs->heaps[i].base;
    737         /* -1 because limit is exclusive but max is inclusive. */
    738         max = MIN((uintptr_t)hs->heaps[i].limit - 1, hs->markBits.max);
    739         aliasBitmap(&liveBits[i], &hs->liveBits, base, max);
    740         aliasBitmap(&markBits[i], &hs->markBits, base, max);
    741     }
    742 }
    743 
    744 /*
    745  * Get the bitmap representing all live objects.
    746  */
    747 HeapBitmap *dvmHeapSourceGetLiveBits(void)
    748 {
    749     HS_BOILERPLATE();
    750 
    751     return &gHs->liveBits;
    752 }
    753 
    754 void dvmHeapSourceSwapBitmaps(void)
    755 {
    756     HeapBitmap tmp;
    757 
    758     tmp = gHs->liveBits;
    759     gHs->liveBits = gHs->markBits;
    760     gHs->markBits = tmp;
    761 }
    762 
    763 void dvmHeapSourceZeroMarkBitmap(void)
    764 {
    765     HS_BOILERPLATE();
    766 
    767     dvmHeapBitmapZero(&gHs->markBits);
    768 }
    769 
    770 void dvmMarkImmuneObjects(const char *immuneLimit)
    771 {
    772     char *dst, *src;
    773     size_t i, index, length;
    774 
    775     /*
    776      * Copy the contents of the live bit vector for immune object
    777      * range into the mark bit vector.
    778      */
    779     /* The only values generated by dvmHeapSourceGetImmuneLimit() */
    780     assert(immuneLimit == gHs->heaps[0].base ||
    781            immuneLimit == NULL);
    782     assert(gHs->liveBits.base == gHs->markBits.base);
    783     assert(gHs->liveBits.bitsLen == gHs->markBits.bitsLen);
    784     /* heap[0] is never immune */
    785     assert(gHs->heaps[0].base >= immuneLimit);
    786     assert(gHs->heaps[0].limit > immuneLimit);
    787 
    788     for (i = 1; i < gHs->numHeaps; ++i) {
    789         if (gHs->heaps[i].base < immuneLimit) {
    790             assert(gHs->heaps[i].limit <= immuneLimit);
    791             /* Compute the number of words to copy in the bitmap. */
    792             index = HB_OFFSET_TO_INDEX(
    793                 (uintptr_t)gHs->heaps[i].base - gHs->liveBits.base);
    794             /* Compute the starting offset in the live and mark bits. */
    795             src = (char *)(gHs->liveBits.bits + index);
    796             dst = (char *)(gHs->markBits.bits + index);
    797             /* Compute the number of bytes of the live bitmap to copy. */
    798             length = HB_OFFSET_TO_BYTE_INDEX(
    799                 gHs->heaps[i].limit - gHs->heaps[i].base);
    800             /* Do the copy. */
    801             memcpy(dst, src, length);
    802             /* Make sure max points to the address of the highest set bit. */
    803             if (gHs->markBits.max < (uintptr_t)gHs->heaps[i].limit) {
    804                 gHs->markBits.max = (uintptr_t)gHs->heaps[i].limit;
    805             }
    806         }
    807     }
    808 }
    809 
    810 /*
    811  * Allocates <n> bytes of zeroed data.
    812  */
    813 void *
    814 dvmHeapSourceAlloc(size_t n)
    815 {
    816     HeapSource *hs = gHs;
    817     Heap *heap;
    818     void *ptr;
    819 
    820     HS_BOILERPLATE();
    821     heap = hs2heap(hs);
    822     if (heap->bytesAllocated + n > hs->softLimit) {
    823         /*
    824          * This allocation would push us over the soft limit; act as
    825          * if the heap is full.
    826          */
    827         LOGV_HEAP("softLimit of %zd.%03zdMB hit for %zd-byte allocation\n",
    828                   FRACTIONAL_MB(hs->softLimit), n);
    829         return NULL;
    830     }
    831     ptr = mspace_calloc(heap->msp, 1, n);
    832     if (ptr == NULL) {
    833         return NULL;
    834     }
    835     countAllocation(heap, ptr, true);
    836     /*
    837      * Check to see if a concurrent GC should be initiated.
    838      */
    839     if (gDvm.gcHeap->gcRunning || !hs->hasGcThread) {
    840         /*
    841          * The garbage collector thread is already running or has yet
    842          * to be started.  Do nothing.
    843          */
    844         return ptr;
    845     }
    846     if (heap->bytesAllocated > heap->concurrentStartBytes) {
    847         /*
    848          * We have exceeded the allocation threshold.  Wake up the
    849          * garbage collector.
    850          */
    851         dvmSignalCond(&gHs->gcThreadCond);
    852     }
    853     return ptr;
    854 }
    855 
    856 /* Remove any hard limits, try to allocate, and shrink back down.
    857  * Last resort when trying to allocate an object.
    858  */
    859 static void *
    860 heapAllocAndGrow(HeapSource *hs, Heap *heap, size_t n)
    861 {
    862     void *ptr;
    863     size_t max;
    864 
    865     /* Grow as much as possible, but don't let the real footprint
    866      * plus external allocations go over the absolute max.
    867      */
    868     max = heap->absoluteMaxSize;
    869     if (max > hs->externalBytesAllocated) {
    870         max -= hs->externalBytesAllocated;
    871 
    872         mspace_set_max_allowed_footprint(heap->msp, max);
    873         ptr = dvmHeapSourceAlloc(n);
    874 
    875         /* Shrink back down as small as possible.  Our caller may
    876          * readjust max_allowed to a more appropriate value.
    877          */
    878         mspace_set_max_allowed_footprint(heap->msp,
    879                 mspace_footprint(heap->msp));
    880     } else {
    881         ptr = NULL;
    882     }
    883 
    884     return ptr;
    885 }
    886 
    887 /*
    888  * Allocates <n> bytes of zeroed data, growing as much as possible
    889  * if necessary.
    890  */
    891 void *
    892 dvmHeapSourceAllocAndGrow(size_t n)
    893 {
    894     HeapSource *hs = gHs;
    895     Heap *heap;
    896     void *ptr;
    897     size_t oldIdealSize;
    898 
    899     HS_BOILERPLATE();
    900     heap = hs2heap(hs);
    901 
    902     ptr = dvmHeapSourceAlloc(n);
    903     if (ptr != NULL) {
    904         return ptr;
    905     }
    906 
    907     oldIdealSize = hs->idealSize;
    908     if (softLimited(hs)) {
    909         /* We're soft-limited.  Try removing the soft limit to
    910          * see if we can allocate without actually growing.
    911          */
    912         hs->softLimit = SIZE_MAX;
    913         ptr = dvmHeapSourceAlloc(n);
    914         if (ptr != NULL) {
    915             /* Removing the soft limit worked;  fix things up to
    916              * reflect the new effective ideal size.
    917              */
    918             snapIdealFootprint();
    919             return ptr;
    920         }
    921         // softLimit intentionally left at SIZE_MAX.
    922     }
    923 
    924     /* We're not soft-limited.  Grow the heap to satisfy the request.
    925      * If this call fails, no footprints will have changed.
    926      */
    927     ptr = heapAllocAndGrow(hs, heap, n);
    928     if (ptr != NULL) {
    929         /* The allocation succeeded.  Fix up the ideal size to
    930          * reflect any footprint modifications that had to happen.
    931          */
    932         snapIdealFootprint();
    933     } else {
    934         /* We just couldn't do it.  Restore the original ideal size,
    935          * fixing up softLimit if necessary.
    936          */
    937         setIdealFootprint(oldIdealSize);
    938     }
    939     return ptr;
    940 }
    941 
    942 /*
    943  * Frees the first numPtrs objects in the ptrs list and returns the
    944  * amount of reclaimed storage. The list must contain addresses all in
    945  * the same mspace, and must be in increasing order. This implies that
    946  * there are no duplicates, and no entries are NULL.
    947  */
    948 size_t dvmHeapSourceFreeList(size_t numPtrs, void **ptrs)
    949 {
    950     Heap *heap;
    951     size_t numBytes;
    952 
    953     HS_BOILERPLATE();
    954 
    955     if (numPtrs == 0) {
    956         return 0;
    957     }
    958 
    959     assert(ptrs != NULL);
    960     assert(*ptrs != NULL);
    961     heap = ptr2heap(gHs, *ptrs);
    962     numBytes = 0;
    963     if (heap != NULL) {
    964         mspace *msp = heap->msp;
    965         // Calling mspace_free on shared heaps disrupts sharing too
    966         // much. For heap[0] -- the 'active heap' -- we call
    967         // mspace_free, but on the other heaps we only do some
    968         // accounting.
    969         if (heap == gHs->heaps) {
    970             // mspace_merge_objects takes two allocated objects, and
    971             // if the second immediately follows the first, will merge
    972             // them, returning a larger object occupying the same
    973             // memory. This is a local operation, and doesn't require
    974             // dlmalloc to manipulate any freelists. It's pretty
    975             // inexpensive compared to free().
    976 
    977             // ptrs is an array of objects all in memory order, and if
    978             // client code has been allocating lots of short-lived
    979             // objects, this is likely to contain runs of objects all
    980             // now garbage, and thus highly amenable to this optimization.
    981 
    982             // Unroll the 0th iteration around the loop below,
    983             // countFree ptrs[0] and initializing merged.
    984             assert(ptrs[0] != NULL);
    985             assert(ptr2heap(gHs, ptrs[0]) == heap);
    986             countFree(heap, ptrs[0], &numBytes);
    987             void *merged = ptrs[0];
    988 
    989             size_t i;
    990             for (i = 1; i < numPtrs; i++) {
    991                 assert(merged != NULL);
    992                 assert(ptrs[i] != NULL);
    993                 assert((intptr_t)merged < (intptr_t)ptrs[i]);
    994                 assert(ptr2heap(gHs, ptrs[i]) == heap);
    995                 countFree(heap, ptrs[i], &numBytes);
    996                 // Try to merge. If it works, merged now includes the
    997                 // memory of ptrs[i]. If it doesn't, free merged, and
    998                 // see if ptrs[i] starts a new run of adjacent
    999                 // objects to merge.
   1000                 if (mspace_merge_objects(msp, merged, ptrs[i]) == NULL) {
   1001                     mspace_free(msp, merged);
   1002                     merged = ptrs[i];
   1003                 }
   1004             }
   1005             assert(merged != NULL);
   1006             mspace_free(msp, merged);
   1007         } else {
   1008             // This is not an 'active heap'. Only do the accounting.
   1009             size_t i;
   1010             for (i = 0; i < numPtrs; i++) {
   1011                 assert(ptrs[i] != NULL);
   1012                 assert(ptr2heap(gHs, ptrs[i]) == heap);
   1013                 countFree(heap, ptrs[i], &numBytes);
   1014             }
   1015         }
   1016     }
   1017     return numBytes;
   1018 }
   1019 
   1020 /*
   1021  * Returns true iff <ptr> is in the heap source.
   1022  */
   1023 bool
   1024 dvmHeapSourceContainsAddress(const void *ptr)
   1025 {
   1026     HS_BOILERPLATE();
   1027 
   1028     return (dvmHeapBitmapCoversAddress(&gHs->liveBits, ptr));
   1029 }
   1030 
   1031 /*
   1032  * Returns true iff <ptr> was allocated from the heap source.
   1033  */
   1034 bool
   1035 dvmHeapSourceContains(const void *ptr)
   1036 {
   1037     HS_BOILERPLATE();
   1038 
   1039     if (dvmHeapSourceContainsAddress(ptr)) {
   1040         return dvmHeapBitmapIsObjectBitSet(&gHs->liveBits, ptr) != 0;
   1041     }
   1042     return false;
   1043 }
   1044 
   1045 /*
   1046  * Returns the value of the requested flag.
   1047  */
   1048 bool
   1049 dvmHeapSourceGetPtrFlag(const void *ptr, enum HeapSourcePtrFlag flag)
   1050 {
   1051     if (ptr == NULL) {
   1052         return false;
   1053     }
   1054 
   1055     if (flag == HS_CONTAINS) {
   1056         return dvmHeapSourceContains(ptr);
   1057     } else if (flag == HS_ALLOCATED_IN_ZYGOTE) {
   1058         HeapSource *hs = gHs;
   1059 
   1060         HS_BOILERPLATE();
   1061 
   1062         if (hs->sawZygote) {
   1063             Heap *heap;
   1064 
   1065             heap = ptr2heap(hs, ptr);
   1066             if (heap != NULL) {
   1067                 /* If the object is not in the active heap, we assume that
   1068                  * it was allocated as part of zygote.
   1069                  */
   1070                 return heap != hs->heaps;
   1071             }
   1072         }
   1073         /* The pointer is outside of any known heap, or we are not
   1074          * running in zygote mode.
   1075          */
   1076         return false;
   1077     }
   1078 
   1079     return false;
   1080 }
   1081 
   1082 /*
   1083  * Returns the number of usable bytes in an allocated chunk; the size
   1084  * may be larger than the size passed to dvmHeapSourceAlloc().
   1085  */
   1086 size_t
   1087 dvmHeapSourceChunkSize(const void *ptr)
   1088 {
   1089     Heap *heap;
   1090 
   1091     HS_BOILERPLATE();
   1092 
   1093     heap = ptr2heap(gHs, ptr);
   1094     if (heap != NULL) {
   1095         return mspace_usable_size(heap->msp, ptr);
   1096     }
   1097     return 0;
   1098 }
   1099 
   1100 /*
   1101  * Returns the number of bytes that the heap source has allocated
   1102  * from the system using sbrk/mmap, etc.
   1103  *
   1104  * Caller must hold the heap lock.
   1105  */
   1106 size_t
   1107 dvmHeapSourceFootprint()
   1108 {
   1109     HS_BOILERPLATE();
   1110 
   1111 //TODO: include size of bitmaps?
   1112     return oldHeapOverhead(gHs, true);
   1113 }
   1114 
   1115 /*
   1116  * Return the real bytes used by old heaps and external memory
   1117  * plus the soft usage of the current heap.  When a soft limit
   1118  * is in effect, this is effectively what it's compared against
   1119  * (though, in practice, it only looks at the current heap).
   1120  */
   1121 static size_t
   1122 getSoftFootprint(bool includeActive)
   1123 {
   1124     HeapSource *hs = gHs;
   1125     size_t ret;
   1126 
   1127     HS_BOILERPLATE();
   1128 
   1129     ret = oldHeapOverhead(hs, false) + hs->externalBytesAllocated;
   1130     if (includeActive) {
   1131         ret += hs->heaps[0].bytesAllocated;
   1132     }
   1133 
   1134     return ret;
   1135 }
   1136 
   1137 /*
   1138  * Gets the maximum number of bytes that the heap source is allowed
   1139  * to allocate from the system.
   1140  */
   1141 size_t
   1142 dvmHeapSourceGetIdealFootprint()
   1143 {
   1144     HeapSource *hs = gHs;
   1145 
   1146     HS_BOILERPLATE();
   1147 
   1148     return hs->idealSize;
   1149 }
   1150 
   1151 /*
   1152  * Sets the soft limit, handling any necessary changes to the allowed
   1153  * footprint of the active heap.
   1154  */
   1155 static void
   1156 setSoftLimit(HeapSource *hs, size_t softLimit)
   1157 {
   1158     /* Compare against the actual footprint, rather than the
   1159      * max_allowed, because the heap may not have grown all the
   1160      * way to the allowed size yet.
   1161      */
   1162     mspace msp = hs->heaps[0].msp;
   1163     size_t currentHeapSize = mspace_footprint(msp);
   1164     if (softLimit < currentHeapSize) {
   1165         /* Don't let the heap grow any more, and impose a soft limit.
   1166          */
   1167         mspace_set_max_allowed_footprint(msp, currentHeapSize);
   1168         hs->softLimit = softLimit;
   1169     } else {
   1170         /* Let the heap grow to the requested max, and remove any
   1171          * soft limit, if set.
   1172          */
   1173         mspace_set_max_allowed_footprint(msp, softLimit);
   1174         hs->softLimit = SIZE_MAX;
   1175     }
   1176 }
   1177 
   1178 /*
   1179  * Sets the maximum number of bytes that the heap source is allowed
   1180  * to allocate from the system.  Clamps to the appropriate maximum
   1181  * value.
   1182  */
   1183 static void
   1184 setIdealFootprint(size_t max)
   1185 {
   1186     HeapSource *hs = gHs;
   1187 #if DEBUG_HEAP_SOURCE
   1188     HeapSource oldHs = *hs;
   1189     mspace msp = hs->heaps[0].msp;
   1190     size_t oldAllowedFootprint =
   1191             mspace_max_allowed_footprint(msp);
   1192 #endif
   1193 
   1194     HS_BOILERPLATE();
   1195 
   1196     if (max > hs->absoluteMaxSize) {
   1197         LOGI_HEAP("Clamp target GC heap from %zd.%03zdMB to %u.%03uMB\n",
   1198                 FRACTIONAL_MB(max),
   1199                 FRACTIONAL_MB(hs->absoluteMaxSize));
   1200         max = hs->absoluteMaxSize;
   1201     } else if (max < hs->minimumSize) {
   1202         max = hs->minimumSize;
   1203     }
   1204 
   1205     /* Convert max into a size that applies to the active heap.
   1206      * Old heaps and external allocations will count against the ideal size.
   1207      */
   1208     size_t overhead = getSoftFootprint(false);
   1209     size_t activeMax;
   1210     if (overhead < max) {
   1211         activeMax = max - overhead;
   1212     } else {
   1213         activeMax = 0;
   1214     }
   1215 
   1216     setSoftLimit(hs, activeMax);
   1217     hs->idealSize = max;
   1218 
   1219     HSTRACE("IDEAL %zd->%zd (%d), soft %zd->%zd (%d), allowed %zd->%zd (%d), "
   1220             "ext %zd\n",
   1221             oldHs.idealSize, hs->idealSize, hs->idealSize - oldHs.idealSize,
   1222             oldHs.softLimit, hs->softLimit, hs->softLimit - oldHs.softLimit,
   1223             oldAllowedFootprint, mspace_max_allowed_footprint(msp),
   1224             mspace_max_allowed_footprint(msp) - oldAllowedFootprint,
   1225             hs->externalBytesAllocated);
   1226 
   1227 }
   1228 
   1229 /*
   1230  * Make the ideal footprint equal to the current footprint.
   1231  */
   1232 static void
   1233 snapIdealFootprint()
   1234 {
   1235     HS_BOILERPLATE();
   1236 
   1237     setIdealFootprint(getSoftFootprint(true));
   1238 }
   1239 
   1240 /*
   1241  * Gets the current ideal heap utilization, represented as a number
   1242  * between zero and one.
   1243  */
   1244 float dvmGetTargetHeapUtilization()
   1245 {
   1246     HeapSource *hs = gHs;
   1247 
   1248     HS_BOILERPLATE();
   1249 
   1250     return (float)hs->targetUtilization / (float)HEAP_UTILIZATION_MAX;
   1251 }
   1252 
   1253 /*
   1254  * Sets the new ideal heap utilization, represented as a number
   1255  * between zero and one.
   1256  */
   1257 void dvmSetTargetHeapUtilization(float newTarget)
   1258 {
   1259     HeapSource *hs = gHs;
   1260 
   1261     HS_BOILERPLATE();
   1262 
   1263     /* Clamp it to a reasonable range.
   1264      */
   1265     // TODO: This may need some tuning.
   1266     if (newTarget < 0.2) {
   1267         newTarget = 0.2;
   1268     } else if (newTarget > 0.8) {
   1269         newTarget = 0.8;
   1270     }
   1271 
   1272     hs->targetUtilization =
   1273             (size_t)(newTarget * (float)HEAP_UTILIZATION_MAX);
   1274     LOGV("Set heap target utilization to %zd/%d (%f)\n",
   1275             hs->targetUtilization, HEAP_UTILIZATION_MAX, newTarget);
   1276 }
   1277 
   1278 /*
   1279  * If set is true, sets the new minimum heap size to size; always
   1280  * returns the current (or previous) size.  If size is negative,
   1281  * removes the current minimum constraint (if present).
   1282  */
   1283 size_t
   1284 dvmMinimumHeapSize(size_t size, bool set)
   1285 {
   1286     HeapSource *hs = gHs;
   1287     size_t oldMinimumSize;
   1288 
   1289     /* gHs caches an entry in gDvm.gcHeap;  we need to hold the
   1290      * heap lock if we're going to look at it.  We also need the
   1291      * lock for the call to setIdealFootprint().
   1292      */
   1293     dvmLockHeap();
   1294 
   1295     HS_BOILERPLATE();
   1296 
   1297     oldMinimumSize = hs->minimumSize;
   1298 
   1299     if (set) {
   1300         /* Don't worry about external allocations right now.
   1301          * setIdealFootprint() will take them into account when
   1302          * minimumSize is used, and it's better to hold onto the
   1303          * intended minimumSize than to clamp it arbitrarily based
   1304          * on the current allocations.
   1305          */
   1306         if (size > hs->absoluteMaxSize) {
   1307             size = hs->absoluteMaxSize;
   1308         }
   1309         hs->minimumSize = size;
   1310         if (size > hs->idealSize) {
   1311             /* Force a snap to the minimum value, which we just set
   1312              * and which setIdealFootprint() will take into consideration.
   1313              */
   1314             setIdealFootprint(hs->idealSize);
   1315         }
   1316         /* Otherwise we'll just keep it in mind the next time
   1317          * setIdealFootprint() is called.
   1318          */
   1319     }
   1320 
   1321     dvmUnlockHeap();
   1322 
   1323     return oldMinimumSize;
   1324 }
   1325 
   1326 /*
   1327  * Given the size of a live set, returns the ideal heap size given
   1328  * the current target utilization and MIN/MAX values.
   1329  *
   1330  * targetUtilization is in the range 1..HEAP_UTILIZATION_MAX.
   1331  */
   1332 static size_t
   1333 getUtilizationTarget(size_t liveSize, size_t targetUtilization)
   1334 {
   1335     size_t targetSize;
   1336 
   1337     /* Use the current target utilization ratio to determine the
   1338      * ideal heap size based on the size of the live set.
   1339      */
   1340     targetSize = (liveSize / targetUtilization) * HEAP_UTILIZATION_MAX;
   1341 
   1342     /* Cap the amount of free space, though, so we don't end up
   1343      * with, e.g., 8MB of free space when the live set size hits 8MB.
   1344      */
   1345     if (targetSize > liveSize + HEAP_IDEAL_FREE) {
   1346         targetSize = liveSize + HEAP_IDEAL_FREE;
   1347     } else if (targetSize < liveSize + HEAP_MIN_FREE) {
   1348         targetSize = liveSize + HEAP_MIN_FREE;
   1349     }
   1350     return targetSize;
   1351 }
   1352 
   1353 /*
   1354  * Given the current contents of the active heap, increase the allowed
   1355  * heap footprint to match the target utilization ratio.  This
   1356  * should only be called immediately after a full mark/sweep.
   1357  */
   1358 void dvmHeapSourceGrowForUtilization()
   1359 {
   1360     HeapSource *hs = gHs;
   1361     Heap *heap;
   1362     size_t targetHeapSize;
   1363     size_t currentHeapUsed;
   1364     size_t oldIdealSize;
   1365     size_t newHeapMax;
   1366     size_t overhead;
   1367     size_t freeBytes;
   1368 
   1369     HS_BOILERPLATE();
   1370     heap = hs2heap(hs);
   1371 
   1372     /* Use the current target utilization ratio to determine the
   1373      * ideal heap size based on the size of the live set.
   1374      * Note that only the active heap plays any part in this.
   1375      *
   1376      * Avoid letting the old heaps influence the target free size,
   1377      * because they may be full of objects that aren't actually
   1378      * in the working set.  Just look at the allocated size of
   1379      * the current heap.
   1380      */
   1381     currentHeapUsed = heap->bytesAllocated;
   1382 #define LET_EXTERNAL_INFLUENCE_UTILIZATION 1
   1383 #if LET_EXTERNAL_INFLUENCE_UTILIZATION
   1384     /* This is a hack to deal with the side-effects of moving
   1385      * bitmap data out of the Dalvik heap.  Since the amount
   1386      * of free space after a GC scales with the size of the
   1387      * live set, many apps expected the large free space that
   1388      * appeared along with megabytes' worth of bitmaps.  When
   1389      * the bitmaps were removed, the free size shrank significantly,
   1390      * and apps started GCing constantly.  This makes it so the
   1391      * post-GC free space is the same size it would have been
   1392      * if the bitmaps were still in the Dalvik heap.
   1393      */
   1394     currentHeapUsed += hs->externalBytesAllocated;
   1395 #endif
   1396     targetHeapSize =
   1397             getUtilizationTarget(currentHeapUsed, hs->targetUtilization);
   1398 #if LET_EXTERNAL_INFLUENCE_UTILIZATION
   1399     currentHeapUsed -= hs->externalBytesAllocated;
   1400     targetHeapSize -= hs->externalBytesAllocated;
   1401 #endif
   1402 
   1403     /* The ideal size includes the old heaps; add overhead so that
   1404      * it can be immediately subtracted again in setIdealFootprint().
   1405      * If the target heap size would exceed the max, setIdealFootprint()
   1406      * will clamp it to a legal value.
   1407      */
   1408     overhead = getSoftFootprint(false);
   1409     oldIdealSize = hs->idealSize;
   1410     setIdealFootprint(targetHeapSize + overhead);
   1411 
   1412     freeBytes = getAllocLimit(hs);
   1413     if (freeBytes < CONCURRENT_MIN_FREE) {
   1414         /* Not enough free memory to allow a concurrent GC. */
   1415         heap->concurrentStartBytes = SIZE_MAX;
   1416     } else {
   1417         heap->concurrentStartBytes = freeBytes - CONCURRENT_START;
   1418     }
   1419     newHeapMax = mspace_max_allowed_footprint(heap->msp);
   1420     if (softLimited(hs)) {
   1421         LOGD_HEAP("GC old usage %zd.%zd%%; now "
   1422                 "%zd.%03zdMB used / %zd.%03zdMB soft max "
   1423                 "(%zd.%03zdMB over, "
   1424                 "%zd.%03zdMB ext, "
   1425                 "%zd.%03zdMB real max)\n",
   1426                 FRACTIONAL_PCT(currentHeapUsed, oldIdealSize),
   1427                 FRACTIONAL_MB(currentHeapUsed),
   1428                 FRACTIONAL_MB(hs->softLimit),
   1429                 FRACTIONAL_MB(overhead),
   1430                 FRACTIONAL_MB(hs->externalBytesAllocated),
   1431                 FRACTIONAL_MB(newHeapMax));
   1432     } else {
   1433         LOGD_HEAP("GC old usage %zd.%zd%%; now "
   1434                 "%zd.%03zdMB used / %zd.%03zdMB real max "
   1435                 "(%zd.%03zdMB over, "
   1436                 "%zd.%03zdMB ext)\n",
   1437                 FRACTIONAL_PCT(currentHeapUsed, oldIdealSize),
   1438                 FRACTIONAL_MB(currentHeapUsed),
   1439                 FRACTIONAL_MB(newHeapMax),
   1440                 FRACTIONAL_MB(overhead),
   1441                 FRACTIONAL_MB(hs->externalBytesAllocated));
   1442     }
   1443 }
   1444 
   1445 /*
   1446  * Return free pages to the system.
   1447  * TODO: move this somewhere else, especially the native heap part.
   1448  */
   1449 
   1450 static void releasePagesInRange(void *start, void *end, void *nbytes)
   1451 {
   1452     /* Linux requires that the madvise() start address is page-aligned.
   1453     * We also align the end address.
   1454     */
   1455     start = (void *)ALIGN_UP_TO_PAGE_SIZE(start);
   1456     end = (void *)((size_t)end & ~(SYSTEM_PAGE_SIZE - 1));
   1457     if (start < end) {
   1458         size_t length = (char *)end - (char *)start;
   1459         madvise(start, length, MADV_DONTNEED);
   1460         *(size_t *)nbytes += length;
   1461     }
   1462 }
   1463 
   1464 /*
   1465  * Return unused memory to the system if possible.
   1466  */
   1467 void
   1468 dvmHeapSourceTrim(size_t bytesTrimmed[], size_t arrayLen)
   1469 {
   1470     HeapSource *hs = gHs;
   1471     size_t nativeBytes, heapBytes;
   1472     size_t i;
   1473 
   1474     HS_BOILERPLATE();
   1475 
   1476     assert(arrayLen >= hs->numHeaps);
   1477 
   1478     heapBytes = 0;
   1479     for (i = 0; i < hs->numHeaps; i++) {
   1480         Heap *heap = &hs->heaps[i];
   1481 
   1482         /* Return the wilderness chunk to the system.
   1483          */
   1484         mspace_trim(heap->msp, 0);
   1485 
   1486         /* Return any whole free pages to the system.
   1487          */
   1488         bytesTrimmed[i] = 0;
   1489         mspace_walk_free_pages(heap->msp, releasePagesInRange,
   1490                                &bytesTrimmed[i]);
   1491         heapBytes += bytesTrimmed[i];
   1492     }
   1493 
   1494     /* Same for the native heap.
   1495      */
   1496     dlmalloc_trim(0);
   1497     nativeBytes = 0;
   1498     dlmalloc_walk_free_pages(releasePagesInRange, &nativeBytes);
   1499 
   1500     LOGD_HEAP("madvised %zd (GC) + %zd (native) = %zd total bytes\n",
   1501             heapBytes, nativeBytes, heapBytes + nativeBytes);
   1502 }
   1503 
   1504 /*
   1505  * Walks over the heap source and passes every allocated and
   1506  * free chunk to the callback.
   1507  */
   1508 void
   1509 dvmHeapSourceWalk(void(*callback)(const void *chunkptr, size_t chunklen,
   1510                                       const void *userptr, size_t userlen,
   1511                                       void *arg),
   1512                   void *arg)
   1513 {
   1514     HeapSource *hs = gHs;
   1515     size_t i;
   1516 
   1517     HS_BOILERPLATE();
   1518 
   1519     /* Walk the heaps from oldest to newest.
   1520      */
   1521 //TODO: do this in address order
   1522     for (i = hs->numHeaps; i > 0; --i) {
   1523         mspace_walk_heap(hs->heaps[i-1].msp, callback, arg);
   1524     }
   1525 }
   1526 
   1527 /*
   1528  * Gets the number of heaps available in the heap source.
   1529  *
   1530  * Caller must hold the heap lock, because gHs caches a field
   1531  * in gDvm.gcHeap.
   1532  */
   1533 size_t
   1534 dvmHeapSourceGetNumHeaps()
   1535 {
   1536     HeapSource *hs = gHs;
   1537 
   1538     HS_BOILERPLATE();
   1539 
   1540     return hs->numHeaps;
   1541 }
   1542 
   1543 
   1544 /*
   1545  * External allocation tracking
   1546  *
   1547  * In some situations, memory outside of the heap is tied to the
   1548  * lifetime of objects in the heap.  Since that memory is kept alive
   1549  * by heap objects, it should provide memory pressure that can influence
   1550  * GCs.
   1551  */
   1552 
   1553 /*
   1554  * Returns true if the requested number of bytes can be allocated from
   1555  * available storage.
   1556  */
   1557 static bool externalBytesAvailable(const HeapSource *hs, size_t numBytes)
   1558 {
   1559     const Heap *heap;
   1560     size_t currentHeapSize, newHeapSize;
   1561 
   1562     /* Make sure that this allocation is even possible.
   1563      * Don't let the external size plus the actual heap size
   1564      * go over the absolute max.  This essentially treats
   1565      * external allocations as part of the active heap.
   1566      *
   1567      * Note that this will fail "mysteriously" if there's
   1568      * a small softLimit but a large heap footprint.
   1569      */
   1570     heap = hs2heap(hs);
   1571     currentHeapSize = mspace_max_allowed_footprint(heap->msp);
   1572     newHeapSize = currentHeapSize + hs->externalBytesAllocated + numBytes;
   1573     if (newHeapSize <= heap->absoluteMaxSize) {
   1574         return true;
   1575     }
   1576     HSTRACE("externalBytesAvailable(): "
   1577             "footprint %zu + extAlloc %zu + n %zu >= max %zu (space for %zu)\n",
   1578             currentHeapSize, hs->externalBytesAllocated, numBytes,
   1579             heap->absoluteMaxSize,
   1580             heap->absoluteMaxSize -
   1581                     (currentHeapSize + hs->externalBytesAllocated));
   1582     return false;
   1583 }
   1584 
   1585 #define EXTERNAL_TARGET_UTILIZATION 820  // 80%
   1586 
   1587 /*
   1588  * Tries to update the internal count of externally-allocated memory.
   1589  * If there's enough room for that memory, returns true.  If not, returns
   1590  * false and does not update the count.
   1591  *
   1592  * The caller must ensure externalBytesAvailable(hs, n) == true.
   1593  */
   1594 static bool
   1595 externalAlloc(HeapSource *hs, size_t n, bool grow)
   1596 {
   1597     assert(hs->externalLimit >= hs->externalBytesAllocated);
   1598 
   1599     HSTRACE("externalAlloc(%zd%s)\n", n, grow ? ", grow" : "");
   1600     assert(externalBytesAvailable(hs, n));  // The caller must ensure this.
   1601 
   1602     /* External allocations have their own "free space" that they
   1603      * can allocate from without causing a GC.
   1604      */
   1605     if (hs->externalBytesAllocated + n <= hs->externalLimit) {
   1606         hs->externalBytesAllocated += n;
   1607 #if PROFILE_EXTERNAL_ALLOCATIONS
   1608         if (gDvm.allocProf.enabled) {
   1609             Thread* self = dvmThreadSelf();
   1610             gDvm.allocProf.externalAllocCount++;
   1611             gDvm.allocProf.externalAllocSize += n;
   1612             if (self != NULL) {
   1613                 self->allocProf.externalAllocCount++;
   1614                 self->allocProf.externalAllocSize += n;
   1615             }
   1616         }
   1617 #endif
   1618         return true;
   1619     }
   1620     if (!grow) {
   1621         return false;
   1622     }
   1623 
   1624     /* GROW */
   1625     hs->externalBytesAllocated += n;
   1626     hs->externalLimit = getUtilizationTarget(
   1627             hs->externalBytesAllocated, EXTERNAL_TARGET_UTILIZATION);
   1628     HSTRACE("EXTERNAL grow limit to %zd\n", hs->externalLimit);
   1629     return true;
   1630 }
   1631 
   1632 static void
   1633 gcForExternalAlloc(bool collectSoftReferences)
   1634 {
   1635     if (gDvm.allocProf.enabled) {
   1636         Thread* self = dvmThreadSelf();
   1637         gDvm.allocProf.gcCount++;
   1638         if (self != NULL) {
   1639             self->allocProf.gcCount++;
   1640         }
   1641     }
   1642     dvmCollectGarbageInternal(collectSoftReferences, GC_EXTERNAL_ALLOC);
   1643 }
   1644 
   1645 /*
   1646  * Returns true if there is enough unused storage to perform an
   1647  * external allocation of the specified size.  If there insufficient
   1648  * free storage we try to releasing memory from external allocations
   1649  * and trimming the heap.
   1650  */
   1651 static bool externalAllocPossible(const HeapSource *hs, size_t n)
   1652 {
   1653     size_t bytesTrimmed[HEAP_SOURCE_MAX_HEAP_COUNT];
   1654 
   1655     /*
   1656      * If there is sufficient space return immediately.
   1657      */
   1658     if (externalBytesAvailable(hs, n)) {
   1659         return true;
   1660     }
   1661     /*
   1662      * There is insufficient space.  Wait for the garbage collector to
   1663      * become inactive before proceeding.
   1664      */
   1665     while (gDvm.gcHeap->gcRunning) {
   1666         dvmWaitForConcurrentGcToComplete();
   1667     }
   1668     /*
   1669      * The heap may have grown or become trimmed while we were
   1670      * waiting.
   1671      */
   1672     if (externalBytesAvailable(hs, n)) {
   1673         return true;
   1674     }
   1675     /*
   1676      * Try a garbage collection that clears soft references.  This may
   1677      * make trimming more effective.
   1678      */
   1679     gcForExternalAlloc(true);
   1680     if (externalBytesAvailable(hs, n)) {
   1681         return true;
   1682     }
   1683     /*
   1684      * Try trimming the mspace to reclaim unused pages.
   1685      */
   1686     dvmHeapSourceTrim(bytesTrimmed, NELEM(bytesTrimmed));
   1687     snapIdealFootprint();
   1688     if (externalBytesAvailable(hs, n)) {
   1689         return true;
   1690     }
   1691     /*
   1692      * Nothing worked, return an error.
   1693      */
   1694     return false;
   1695 }
   1696 
   1697 /*
   1698  * Updates the internal count of externally-allocated memory.  If there's
   1699  * enough room for that memory, returns true.  If not, returns false and
   1700  * does not update the count.
   1701  *
   1702  * May cause a GC as a side-effect.
   1703  */
   1704 bool
   1705 dvmTrackExternalAllocation(size_t n)
   1706 {
   1707     HeapSource *hs = gHs;
   1708     bool ret = false;
   1709 
   1710     /* gHs caches an entry in gDvm.gcHeap;  we need to hold the
   1711      * heap lock if we're going to look at it.
   1712      */
   1713     dvmLockHeap();
   1714 
   1715     HS_BOILERPLATE();
   1716     assert(hs->externalLimit >= hs->externalBytesAllocated);
   1717 
   1718     /*
   1719      * The externalAlloc calls require the externalAllocPossible
   1720      * invariant to be established.
   1721      */
   1722     if (!externalAllocPossible(hs, n)) {
   1723         LOGE_HEAP("%zd-byte external allocation "
   1724                   "too large for this process.", n);
   1725         goto out;
   1726     }
   1727 
   1728     /* Try "allocating" using the existing "free space".
   1729      */
   1730     HSTRACE("EXTERNAL alloc %zu (%zu < %zu)\n",
   1731             n, hs->externalBytesAllocated, hs->externalLimit);
   1732     if (externalAlloc(hs, n, false)) {
   1733         ret = true;
   1734         goto out;
   1735     }
   1736     /*
   1737      * Wait until garbage collector is quiescent before proceeding.
   1738      */
   1739     while (gDvm.gcHeap->gcRunning) {
   1740         dvmWaitForConcurrentGcToComplete();
   1741     }
   1742     /*
   1743      * Re-establish the invariant if it was lost while we were
   1744      * waiting.
   1745      */
   1746     if (!externalAllocPossible(hs, n)) {
   1747         LOGE_HEAP("%zd-byte external allocation "
   1748                   "too large for this process.", n);
   1749         goto out;
   1750     }
   1751     /* The "allocation" failed.  Free up some space by doing
   1752      * a full garbage collection.  This may grow the heap source
   1753      * if the live set is sufficiently large.
   1754      */
   1755     HSTRACE("EXTERNAL alloc %zd: GC 1\n", n);
   1756     gcForExternalAlloc(false);  // don't collect SoftReferences
   1757     if (externalAlloc(hs, n, false)) {
   1758         ret = true;
   1759         goto out;
   1760     }
   1761 
   1762     /* Even that didn't work;  this is an exceptional state.
   1763      * Try harder, growing the heap source if necessary.
   1764      */
   1765     HSTRACE("EXTERNAL alloc %zd: frag\n", n);
   1766     ret = externalAlloc(hs, n, true);
   1767     if (ret) {
   1768         goto out;
   1769     }
   1770 
   1771     /* We couldn't even grow enough to satisfy the request.
   1772      * Try one last GC, collecting SoftReferences this time.
   1773      */
   1774     HSTRACE("EXTERNAL alloc %zd: GC 2\n", n);
   1775     gcForExternalAlloc(true);  // collect SoftReferences
   1776     ret = externalAlloc(hs, n, true);
   1777     if (!ret) {
   1778         LOGE_HEAP("Out of external memory on a %zu-byte allocation.\n", n);
   1779     }
   1780 
   1781 #if PROFILE_EXTERNAL_ALLOCATIONS
   1782     if (gDvm.allocProf.enabled) {
   1783         Thread* self = dvmThreadSelf();
   1784         gDvm.allocProf.failedExternalAllocCount++;
   1785         gDvm.allocProf.failedExternalAllocSize += n;
   1786         if (self != NULL) {
   1787             self->allocProf.failedExternalAllocCount++;
   1788             self->allocProf.failedExternalAllocSize += n;
   1789         }
   1790     }
   1791 #endif
   1792 
   1793 out:
   1794     dvmUnlockHeap();
   1795 
   1796     return ret;
   1797 }
   1798 
   1799 /*
   1800  * Reduces the internal count of externally-allocated memory.
   1801  */
   1802 void
   1803 dvmTrackExternalFree(size_t n)
   1804 {
   1805     HeapSource *hs = gHs;
   1806     size_t newExternalLimit;
   1807     size_t oldExternalBytesAllocated;
   1808 
   1809     HSTRACE("EXTERNAL free %zu (%zu < %zu)\n",
   1810             n, hs->externalBytesAllocated, hs->externalLimit);
   1811 
   1812     /* gHs caches an entry in gDvm.gcHeap;  we need to hold the
   1813      * heap lock if we're going to look at it.
   1814      */
   1815     dvmLockHeap();
   1816 
   1817     HS_BOILERPLATE();
   1818     assert(hs->externalLimit >= hs->externalBytesAllocated);
   1819 
   1820     oldExternalBytesAllocated = hs->externalBytesAllocated;
   1821     if (n <= hs->externalBytesAllocated) {
   1822         hs->externalBytesAllocated -= n;
   1823     } else {
   1824         n = hs->externalBytesAllocated;
   1825         hs->externalBytesAllocated = 0;
   1826     }
   1827 
   1828 #if PROFILE_EXTERNAL_ALLOCATIONS
   1829     if (gDvm.allocProf.enabled) {
   1830         Thread* self = dvmThreadSelf();
   1831         gDvm.allocProf.externalFreeCount++;
   1832         gDvm.allocProf.externalFreeSize += n;
   1833         if (self != NULL) {
   1834             self->allocProf.externalFreeCount++;
   1835             self->allocProf.externalFreeSize += n;
   1836         }
   1837     }
   1838 #endif
   1839 
   1840     /* Shrink as quickly as we can.
   1841      */
   1842     newExternalLimit = getUtilizationTarget(
   1843             hs->externalBytesAllocated, EXTERNAL_TARGET_UTILIZATION);
   1844     if (newExternalLimit < oldExternalBytesAllocated) {
   1845         /* Make sure that the remaining free space is at least
   1846          * big enough to allocate something of the size that was
   1847          * just freed.  This makes it more likely that
   1848          *     externalFree(N); externalAlloc(N);
   1849          * will work without causing a GC.
   1850          */
   1851         HSTRACE("EXTERNAL free preserved %zu extra free bytes\n",
   1852                 oldExternalBytesAllocated - newExternalLimit);
   1853         newExternalLimit = oldExternalBytesAllocated;
   1854     }
   1855     if (newExternalLimit < hs->externalLimit) {
   1856         hs->externalLimit = newExternalLimit;
   1857     }
   1858 
   1859     dvmUnlockHeap();
   1860 }
   1861 
   1862 /*
   1863  * Returns the number of externally-allocated bytes being tracked by
   1864  * dvmTrackExternalAllocation/Free().
   1865  */
   1866 size_t
   1867 dvmGetExternalBytesAllocated()
   1868 {
   1869     const HeapSource *hs = gHs;
   1870     size_t ret;
   1871 
   1872     /* gHs caches an entry in gDvm.gcHeap;  we need to hold the
   1873      * heap lock if we're going to look at it.  We also need the
   1874      * lock for the call to setIdealFootprint().
   1875      */
   1876     dvmLockHeap();
   1877     HS_BOILERPLATE();
   1878     ret = hs->externalBytesAllocated;
   1879     dvmUnlockHeap();
   1880 
   1881     return ret;
   1882 }
   1883 
   1884 void *dvmHeapSourceGetImmuneLimit(GcMode mode)
   1885 {
   1886     if (mode == GC_PARTIAL) {
   1887         return hs2heap(gHs)->base;
   1888     } else {
   1889         return NULL;
   1890     }
   1891 }
   1892