/* Remove any hard limits, try to allocate, and shrink back down. * Last resort when trying to allocate an object. */ static void* heapAllocAndGrow(HeapSource *hs, Heap *heap, size_t n) { /* Grow as much as possible, but don't let the real footprint * go over the absolute max. */ size_t max = heap->maximumSize; mspace_set_footprint_limit(heap->msp, max); void* ptr = dvmHeapSourceAlloc(n); /* Shrink back down as small as possible. Our caller may * readjust max_allowed to a more appropriate value. */ mspace_set_footprint_limit(heap->msp, mspace_footprint(heap->msp)); return ptr; }
/* * Adds an additional heap to the heap source. Returns false if there * are too many heaps or insufficient free space to add another heap. */ static bool addNewHeap(HeapSource *hs) { Heap heap; assert(hs != NULL); if (hs->numHeaps >= HEAP_SOURCE_MAX_HEAP_COUNT) { ALOGE("Attempt to create too many heaps (%zd >= %zd)", hs->numHeaps, HEAP_SOURCE_MAX_HEAP_COUNT); dvmAbort(); return false; } memset(&heap, 0, sizeof(heap)); /* * Heap storage comes from a common virtual memory reservation. * The new heap will start on the page after the old heap. */ char *base = hs->heaps[0].brk; size_t overhead = base - hs->heaps[0].base; assert(((size_t)hs->heaps[0].base & (SYSTEM_PAGE_SIZE - 1)) == 0); if (overhead + hs->minFree >= hs->maximumSize) { LOGE_HEAP("No room to create any more heaps " "(%zd overhead, %zd max)", overhead, hs->maximumSize); return false; } size_t morecoreStart = SYSTEM_PAGE_SIZE; heap.maximumSize = hs->growthLimit - overhead; heap.concurrentStartBytes = hs->minFree - CONCURRENT_START; heap.base = base; heap.limit = heap.base + heap.maximumSize; heap.brk = heap.base + morecoreStart; if (!remapNewHeap(hs, &heap)) { return false; } heap.msp = createMspace(base, morecoreStart, hs->minFree); if (heap.msp == NULL) { return false; } /* Don't let the soon-to-be-old heap grow any further. */ hs->heaps[0].maximumSize = overhead; hs->heaps[0].limit = base; mspace_set_footprint_limit(hs->heaps[0].msp, overhead); /* Put the new heap in the list, at heaps[0]. * Shift existing heaps down. */ memmove(&hs->heaps[1], &hs->heaps[0], hs->numHeaps * sizeof(hs->heaps[0])); hs->heaps[0] = heap; hs->numHeaps++; return true; }
/* * Sets the soft limit, handling any necessary changes to the allowed * footprint of the active heap. */ static void setSoftLimit(HeapSource *hs, size_t softLimit) { /* Compare against the actual footprint, rather than the * max_allowed, because the heap may not have grown all the * way to the allowed size yet. */ mspace msp = hs->heaps[0].msp; size_t currentHeapSize = mspace_footprint(msp); if (softLimit < currentHeapSize) { /* Don't let the heap grow any more, and impose a soft limit. */ mspace_set_footprint_limit(msp, currentHeapSize); hs->softLimit = softLimit; } else { /* Let the heap grow to the requested max, and remove any * soft limit, if set. */ mspace_set_footprint_limit(msp, softLimit); hs->softLimit = SIZE_MAX; } }
static mspace createMspace(void* begin, size_t morecoreStart, size_t startingSize) { // Clear errno to allow strerror on error. errno = 0; // Allow access to inital pages that will hold mspace. mprotect(begin, morecoreStart, PROT_READ | PROT_WRITE); // Create mspace using our backing storage starting at begin and with a footprint of // morecoreStart. Don't use an internal dlmalloc lock. When morecoreStart bytes of memory are // exhausted morecore will be called. mspace msp = create_mspace_with_base(begin, morecoreStart, false /*locked*/); if (msp != NULL) { // Do not allow morecore requests to succeed beyond the starting size of the heap. mspace_set_footprint_limit(msp, startingSize); } else { ALOGE("create_mspace_with_base failed %s", strerror(errno)); } return msp; }
static mspace getMspace() { if (gExecutableStore == NULL) { int fd = ashmem_create_region("CodeFlinger code cache", kMaxCodeCacheCapacity); LOG_ALWAYS_FATAL_IF(fd < 0, "Creating code cache, ashmem_create_region " "failed with error '%s'", strerror(errno)); gExecutableStore = mmap(NULL, kMaxCodeCacheCapacity, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, fd, 0); LOG_ALWAYS_FATAL_IF(gExecutableStore == MAP_FAILED, "Creating code cache, mmap failed with error " "'%s'", strerror(errno)); close(fd); gMspace = create_mspace_with_base(gExecutableStore, kMaxCodeCacheCapacity, /*locked=*/ false); mspace_set_footprint_limit(gMspace, kMaxCodeCacheCapacity); } return gMspace; }
size_t mm_mspace_setfootprint_limit(mm_mspace_t space, size_t size) { return mspace_set_footprint_limit(space.opaque, size); }