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; }
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; }
/* Find unreachable objects that need to be finalized, * and schedule them for finalization. */ void dvmHeapScheduleFinalizations() { HeapRefTable newPendingRefs; LargeHeapRefTable *finRefs = gDvm.gcHeap->finalizableRefs; Object **ref; Object **lastRef; size_t totalPendCount; GcMarkContext *markContext = &gDvm.gcHeap->markContext; /* * All reachable objects have been marked. * Any unmarked finalizable objects need to be finalized. */ /* Create a table that the new pending refs will * be added to. */ if (!dvmHeapInitHeapRefTable(&newPendingRefs, 128)) { //TODO: mark all finalizable refs and hope that // we can schedule them next time. Watch out, // because we may be expecting to free up space // by calling finalizers. LOGE_GC("dvmHeapScheduleFinalizations(): no room for " "pending finalizations\n"); dvmAbort(); } /* Walk through finalizableRefs and move any unmarked references * to the list of new pending refs. */ totalPendCount = 0; while (finRefs != NULL) { Object **gapRef; size_t newPendCount = 0; gapRef = ref = finRefs->refs.table; lastRef = finRefs->refs.nextEntry; while (ref < lastRef) { DvmHeapChunk *hc; hc = ptr2chunk(*ref); if (!isMarked(hc, markContext)) { if (!dvmHeapAddToHeapRefTable(&newPendingRefs, *ref)) { //TODO: add the current table and allocate // a new, smaller one. LOGE_GC("dvmHeapScheduleFinalizations(): " "no room for any more pending finalizations: %zd\n", dvmHeapNumHeapRefTableEntries(&newPendingRefs)); dvmAbort(); } newPendCount++; } else { /* This ref is marked, so will remain on finalizableRefs. */ if (newPendCount > 0) { /* Copy it up to fill the holes. */ *gapRef++ = *ref; } else { /* No holes yet; don't bother copying. */ gapRef++; } } ref++; } finRefs->refs.nextEntry = gapRef; //TODO: if the table is empty when we're done, free it. totalPendCount += newPendCount; finRefs = finRefs->next; } LOGD_GC("dvmHeapScheduleFinalizations(): %zd finalizers triggered.\n", totalPendCount); if (totalPendCount == 0) { /* No objects required finalization. * Free the empty temporary table. */ dvmClearReferenceTable(&newPendingRefs); return; } /* Add the new pending refs to the main list. */ if (!dvmHeapAddTableToLargeTable(&gDvm.gcHeap->pendingFinalizationRefs, &newPendingRefs)) { LOGE_GC("dvmHeapScheduleFinalizations(): can't insert new " "pending finalizations\n"); dvmAbort(); } //TODO: try compacting the main list with a memcpy loop /* Mark the refs we just moved; we don't want them or their * children to get swept yet. */ ref = newPendingRefs.table; lastRef = newPendingRefs.nextEntry; assert(ref < lastRef); HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_FINALIZING, 0); while (ref < lastRef) { markObjectNonNull(*ref, markContext); ref++; } HPROF_CLEAR_GC_SCAN_STATE(); /* Set markAllReferents so that we don't collect referents whose * only references are in final-reachable objects. * TODO: eventually provide normal reference behavior by properly * marking these references. */ gDvm.gcHeap->markAllReferents = true; processMarkStack(markContext); gDvm.gcHeap->markAllReferents = false; dvmSignalHeapWorker(false); }