Ejemplo n.º 1
0
static bool
createMarkStack(GcMarkStack *stack)
{
    const Object **limit;
    size_t size;
    int fd;

    /* Create a stack big enough for the worst possible case,
     * where the heap is perfectly full of the smallest object.
     * TODO: be better about memory usage; use a smaller stack with
     *       overflow detection and recovery.
     */
    size = dvmHeapSourceGetIdealFootprint() /
            (sizeof(Object) + HEAP_SOURCE_CHUNK_OVERHEAD);
    size = ALIGN_UP_TO_PAGE_SIZE(size);
    fd = ashmem_create_region("dalvik-heap-markstack", size);
    if (fd < 0) {
        LOGE_GC("Could not create %d-byte ashmem mark stack\n", size);
        return false;
    }
    limit = (const Object **)mmap(NULL, size, PROT_READ | PROT_WRITE,
            MAP_PRIVATE, fd, 0);
    close(fd);
    if (limit == MAP_FAILED) {
        LOGE_GC("Could not mmap %d-byte ashmem mark stack\n", size);
        return false;
    }

    memset(stack, 0, sizeof(*stack));
    stack->limit = limit;
    stack->base = (const Object **)((uintptr_t)limit + size);
    stack->top = stack->base;

    return true;
}
Ejemplo n.º 2
0
static bool createMarkStack(GcMarkStack *stack)
{
    const Object **limit;
    const char *name;
    size_t size;

    /* Create a stack big enough for the worst possible case,
     * where the heap is perfectly full of the smallest object.
     * TODO: be better about memory usage; use a smaller stack with
     *       overflow detection and recovery.
     */
    size = dvmHeapSourceGetIdealFootprint() * sizeof(Object*) /
            (sizeof(Object) + HEAP_SOURCE_CHUNK_OVERHEAD);
    size = ALIGN_UP_TO_PAGE_SIZE(size);
    name = "dalvik-mark-stack";
    limit = dvmAllocRegion(size, PROT_READ | PROT_WRITE, name);
    if (limit == NULL) {
        LOGE_GC("Could not mmap %zd-byte ashmem region '%s'", size, name);
        return false;
    }
    stack->limit = limit;
    stack->base = (const Object **)((uintptr_t)limit + size);
    stack->top = stack->base;
    return true;
}
Ejemplo n.º 3
0
/*
 * Initializes the stack top and advises the mark stack pages as needed.
 */
static bool createMarkStack(GcMarkStack *stack)
{
    assert(stack != NULL);
    size_t length = dvmHeapSourceGetIdealFootprint() * sizeof(Object*) /
        (sizeof(Object) + HEAP_SOURCE_CHUNK_OVERHEAD);
    madvise(stack->base, length, MADV_NORMAL);
    stack->top = stack->base;
    return true;
}
Ejemplo n.º 4
0
/* Try as hard as possible to allocate some memory.
 */
static void *tryMalloc(size_t size)
{
    void *ptr;

    /* Don't try too hard if there's no way the allocation is
     * going to succeed.  We have to collect SoftReferences before
     * throwing an OOME, though.
     */
    if (size >= gDvm.heapGrowthLimit) {
        ALOGW("%zd byte allocation exceeds the %zd byte maximum heap size",
             size, gDvm.heapGrowthLimit);
        ptr = NULL;
        goto collect_soft_refs;
    }

//TODO: figure out better heuristics
//    There will be a lot of churn if someone allocates a bunch of
//    big objects in a row, and we hit the frag case each time.
//    A full GC for each.
//    Maybe we grow the heap in bigger leaps
//    Maybe we skip the GC if the size is large and we did one recently
//      (number of allocations ago) (watch for thread effects)
//    DeflateTest allocs a bunch of ~128k buffers w/in 0-5 allocs of each other
//      (or, at least, there are only 0-5 objects swept each time)

    ptr = dvmHeapSourceAlloc(size);
    if (ptr != NULL) {
        return ptr;
    }

    /*
     * The allocation failed.  If the GC is running, block until it
     * completes and retry.
     */
    if (gDvm.gcHeap->gcRunning) {
        /*
         * The GC is concurrently tracing the heap.  Release the heap
         * lock, wait for the GC to complete, and retrying allocating.
         */
        dvmWaitForConcurrentGcToComplete();
        ptr = dvmHeapSourceAlloc(size);
        if (ptr != NULL) {
            return ptr;
        }
    }
    /*
     * Another failure.  Our thread was starved or there may be too
     * many live objects.  Try a foreground GC.  This will have no
     * effect if the concurrent GC is already running.
     */
    gcForMalloc(false);
    ptr = dvmHeapSourceAlloc(size);
    if (ptr != NULL) {
        return ptr;
    }

    /* Even that didn't work;  this is an exceptional state.
     * Try harder, growing the heap if necessary.
     */
    ptr = dvmHeapSourceAllocAndGrow(size);
    if (ptr != NULL) {
        size_t newHeapSize;

        newHeapSize = dvmHeapSourceGetIdealFootprint();
//TODO: may want to grow a little bit more so that the amount of free
//      space is equal to the old free space + the utilization slop for
//      the new allocation.
        LOGI_HEAP("Grow heap (frag case) to "
                "%zu.%03zuMB for %zu-byte allocation",
                FRACTIONAL_MB(newHeapSize), size);
        return ptr;
    }

    /* Most allocations should have succeeded by now, so the heap
     * is really full, really fragmented, or the requested size is
     * really big.  Do another GC, collecting SoftReferences this
     * time.  The VM spec requires that all SoftReferences have
     * been collected and cleared before throwing an OOME.
     */
//TODO: wait for the finalizers from the previous GC to finish
collect_soft_refs:
    LOGI_HEAP("Forcing collection of SoftReferences for %zu-byte allocation",
            size);
    gcForMalloc(true);
    ptr = dvmHeapSourceAllocAndGrow(size);
    if (ptr != NULL) {
        return ptr;
    }
//TODO: maybe wait for finalizers and try one last time

    LOGE_HEAP("Out of memory on a %zd-byte allocation.", size);
//TODO: tell the HeapSource to dump its state
    dvmDumpThread(dvmThreadSelf(), false);

    return NULL;
}
Ejemplo n.º 5
0
void dvmLogGcStats(size_t numFreed, size_t sizeFreed, size_t gcTimeMs)
{
    size_t perHeapActualSize[HEAP_SOURCE_MAX_HEAP_COUNT],
           perHeapAllowedSize[HEAP_SOURCE_MAX_HEAP_COUNT],
           perHeapNumAllocated[HEAP_SOURCE_MAX_HEAP_COUNT],
           perHeapSizeAllocated[HEAP_SOURCE_MAX_HEAP_COUNT];
    unsigned char eventBuf[1 + (1 + sizeof(long long)) * 4];
    size_t actualSize, allowedSize, numAllocated, sizeAllocated;
    size_t softLimit = dvmHeapSourceGetIdealFootprint();
    size_t nHeaps = dvmHeapSourceGetNumHeaps();

    /* Enough to quiet down gcc for unitialized variable check */
    perHeapActualSize[0] = perHeapAllowedSize[0] = perHeapNumAllocated[0] =
                           perHeapSizeAllocated[0] = 0;
    actualSize = dvmHeapSourceGetValue(HS_FOOTPRINT, perHeapActualSize,
                                       HEAP_SOURCE_MAX_HEAP_COUNT);
    allowedSize = dvmHeapSourceGetValue(HS_ALLOWED_FOOTPRINT,
                      perHeapAllowedSize, HEAP_SOURCE_MAX_HEAP_COUNT);
    numAllocated = dvmHeapSourceGetValue(HS_OBJECTS_ALLOCATED,
                      perHeapNumAllocated, HEAP_SOURCE_MAX_HEAP_COUNT);
    sizeAllocated = dvmHeapSourceGetValue(HS_BYTES_ALLOCATED,
                      perHeapSizeAllocated, HEAP_SOURCE_MAX_HEAP_COUNT);

    /*
     * Construct the the first 64-bit value to write to the log.
     * Global information:
     *
     * [63   ] Must be zero
     * [62-24] ASCII process identifier
     * [23-12] GC time in ms
     * [11- 0] Bytes freed
     *
     */
    long long event0;
    event0 = 0LL << 63 |
            (long long)intToFloat12(gcTimeMs) << 12 |
            (long long)intToFloat12(sizeFreed);
    insertProcessName(&event0);

    /*
     * Aggregated heap stats:
     *
     * [63-62] 10
     * [61-60] Reserved; must be zero
     * [59-48] Objects freed
     * [47-36] Actual size (current footprint)
     * [35-24] Allowed size (current hard max)
     * [23-12] Objects allocated
     * [11- 0] Bytes allocated
     */
    long long event1;
    event1 = 2LL << 62 |
            (long long)intToFloat12(numFreed) << 48 |
            (long long)intToFloat12(actualSize) << 36 |
            (long long)intToFloat12(allowedSize) << 24 |
            (long long)intToFloat12(numAllocated) << 12 |
            (long long)intToFloat12(sizeAllocated);

    /*
     * Report the current state of the zygote heap(s).
     *
     * The active heap is always heap[0].  We can be in one of three states
     * at present:
     *
     *  (1) Still in the zygote.  Zygote using heap[0].
     *  (2) In the zygote, when the first child is started.  We created a
     *      new heap just before the first fork() call, so the original
     *      "zygote heap" is now heap[1], and we have a small heap[0] for
     *      anything we do from here on.
     *  (3) In an app process.  The app gets a new heap[0], and can also
     *      see the two zygote heaps [1] and [2] (probably unwise to
     *      assume any specific ordering).
     *
     * So if nHeaps == 1, we want the stats from heap[0]; else we want
     * the sum of the values from heap[1] to heap[nHeaps-1].
     *
     *
     * Zygote heap stats (except for the soft limit, which belongs to the
     * active heap):
     *
     * [63-62] 11
     * [61-60] Reserved; must be zero
     * [59-48] Soft Limit (for the active heap)
     * [47-36] Actual size (current footprint)
     * [35-24] Allowed size (current hard max)
     * [23-12] Objects allocated
     * [11- 0] Bytes allocated
     */
    long long event2;
    size_t zActualSize, zAllowedSize, zNumAllocated, zSizeAllocated;
    int firstHeap = (nHeaps == 1) ? 0 : 1;
    size_t hh;

    zActualSize = zAllowedSize = zNumAllocated = zSizeAllocated = 0;
    for (hh = firstHeap; hh < nHeaps; hh++) {
        zActualSize += perHeapActualSize[hh];
        zAllowedSize += perHeapAllowedSize[hh];
        zNumAllocated += perHeapNumAllocated[hh];
        zSizeAllocated += perHeapSizeAllocated[hh];
    }
    event2 = 3LL << 62 |
            (long long)intToFloat12(softLimit) << 48 |
            (long long)intToFloat12(zActualSize) << 36 |
            (long long)intToFloat12(zAllowedSize) << 24 |
            (long long)intToFloat12(zNumAllocated) << 12 |
            (long long)intToFloat12(zSizeAllocated);

    /*
     * Report the current external allocation stats and the native heap
     * summary.
     *
     * [63-48] Reserved; must be zero (TODO: put new data in these slots)
     * [47-36] dlmalloc_footprint
     * [35-24] mallinfo: total allocated space
     * [23-12] External byte limit
     * [11- 0] External bytes allocated
     */
    long long event3;
    size_t externalLimit, externalBytesAllocated;
    size_t uordblks, footprint;

#if 0
    /*
     * This adds 2-5msec to the GC cost on a DVT, or about 2-3% of the cost
     * of a GC, so it's not horribly expensive but it's not free either.
     */
    extern size_t dlmalloc_footprint(void);
    struct mallinfo mi;
    //u8 start, end;

    //start = dvmGetRelativeTimeNsec();
    mi = mallinfo();
    uordblks = mi.uordblks;
    footprint = dlmalloc_footprint();
    //end = dvmGetRelativeTimeNsec();
    //LOGD("mallinfo+footprint took %dusec; used=%zd footprint=%zd\n",
    //    (int)((end - start) / 1000), mi.uordblks, footprint);
#else
    uordblks = footprint = 0;
#endif

    externalLimit =
            dvmHeapSourceGetValue(HS_EXTERNAL_LIMIT, NULL, 0);
    externalBytesAllocated =
            dvmHeapSourceGetValue(HS_EXTERNAL_BYTES_ALLOCATED, NULL, 0);
    event3 =
            (long long)intToFloat12(footprint) << 36 |
            (long long)intToFloat12(uordblks) << 24 |
            (long long)intToFloat12(externalLimit) << 12 |
            (long long)intToFloat12(externalBytesAllocated);

    /* Build the event data.
     * [ 0: 0] item count (4)
     * [ 1: 1] EVENT_TYPE_LONG
     * [ 2: 9] event0
     * [10:10] EVENT_TYPE_LONG
     * [11:18] event1
     * [19:19] EVENT_TYPE_LONG
     * [20:27] event2
     * [28:28] EVENT_TYPE_LONG
     * [29:36] event2
     */
    unsigned char *c = eventBuf;
    *c++ = 4;
    *c++ = EVENT_TYPE_LONG;
    memcpy(c, &event0, sizeof(event0));
    c += sizeof(event0);
    *c++ = EVENT_TYPE_LONG;
    memcpy(c, &event1, sizeof(event1));
    c += sizeof(event1);
    *c++ = EVENT_TYPE_LONG;
    memcpy(c, &event2, sizeof(event2));
    c += sizeof(event2);
    *c++ = EVENT_TYPE_LONG;
    memcpy(c, &event3, sizeof(event3));

    (void) android_btWriteLog(EVENT_LOG_TAG_dvm_gc_info, EVENT_TYPE_LIST,
            eventBuf, sizeof(eventBuf));
}