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 <stdint.h> 18 #include <sys/mman.h> 19 #include <errno.h> 20 #include <cutils/ashmem.h> 21 22 #define SIZE_MAX UINT_MAX // TODO: get SIZE_MAX from stdint.h 23 24 #include "Dalvik.h" 25 #include "alloc/DlMalloc.h" 26 #include "alloc/Heap.h" 27 #include "alloc/HeapInternal.h" 28 #include "alloc/HeapSource.h" 29 #include "alloc/HeapBitmap.h" 30 #include "alloc/HeapBitmapInlines.h" 31 32 static void dvmHeapSourceUpdateMaxNativeFootprint(); 33 static void snapIdealFootprint(); 34 static void setIdealFootprint(size_t max); 35 static size_t getMaximumSize(const HeapSource *hs); 36 static void trimHeaps(); 37 38 #define HEAP_UTILIZATION_MAX 1024 39 40 /* How long to wait after a GC before performing a heap trim 41 * operation to reclaim unused pages. 42 */ 43 #define HEAP_TRIM_IDLE_TIME_MS (5 * 1000) 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 struct Heap { 63 /* The mspace to allocate from. 64 */ 65 mspace msp; 66 67 /* The largest size that this heap is allowed to grow to. 68 */ 69 size_t maximumSize; 70 71 /* Number of bytes allocated from this mspace for objects, 72 * including any overhead. This value is NOT exact, and 73 * should only be used as an input for certain heuristics. 74 */ 75 size_t bytesAllocated; 76 77 /* Number of bytes allocated from this mspace at which a 78 * concurrent garbage collection will be started. 79 */ 80 size_t concurrentStartBytes; 81 82 /* Number of objects currently allocated from this mspace. 83 */ 84 size_t objectsAllocated; 85 86 /* 87 * The lowest address of this heap, inclusive. 88 */ 89 char *base; 90 91 /* 92 * The highest address of this heap, exclusive. 93 */ 94 char *limit; 95 96 /* 97 * If the heap has an mspace, the current high water mark in 98 * allocations requested via dvmHeapSourceMorecore. 99 */ 100 char *brk; 101 }; 102 103 struct HeapSource { 104 /* Target ideal heap utilization ratio; range 1..HEAP_UTILIZATION_MAX 105 */ 106 size_t targetUtilization; 107 108 /* The starting heap size. 109 */ 110 size_t startSize; 111 112 /* The largest that the heap source as a whole is allowed to grow. 113 */ 114 size_t maximumSize; 115 116 /* 117 * The largest size we permit the heap to grow. This value allows 118 * the user to limit the heap growth below the maximum size. This 119 * is a work around until we can dynamically set the maximum size. 120 * This value can range between the starting size and the maximum 121 * size but should never be set below the current footprint of the 122 * heap. 123 */ 124 size_t growthLimit; 125 126 /* The desired max size of the heap source as a whole. 127 */ 128 size_t idealSize; 129 130 /* The maximum number of bytes allowed to be allocated from the 131 * active heap before a GC is forced. This is used to "shrink" the 132 * heap in lieu of actual compaction. 133 */ 134 size_t softLimit; 135 136 /* Minimum number of free bytes. Used with the target utilization when 137 * setting the softLimit. Never allows less bytes than this to be free 138 * when the heap size is below the maximum size or growth limit. 139 */ 140 size_t minFree; 141 142 /* Maximum number of free bytes. Used with the target utilization when 143 * setting the softLimit. Never allows more bytes than this to be free 144 * when the heap size is below the maximum size or growth limit. 145 */ 146 size_t maxFree; 147 148 /* The heaps; heaps[0] is always the active heap, 149 * which new objects should be allocated from. 150 */ 151 Heap heaps[HEAP_SOURCE_MAX_HEAP_COUNT]; 152 153 /* The current number of heaps. 154 */ 155 size_t numHeaps; 156 157 /* True if zygote mode was active when the HeapSource was created. 158 */ 159 bool sawZygote; 160 161 /* 162 * The base address of the virtual memory reservation. 163 */ 164 char *heapBase; 165 166 /* 167 * The length in bytes of the virtual memory reservation. 168 */ 169 size_t heapLength; 170 171 /* 172 * The live object bitmap. 173 */ 174 HeapBitmap liveBits; 175 176 /* 177 * The mark bitmap. 178 */ 179 HeapBitmap markBits; 180 181 /* 182 * Native allocations. 183 */ 184 int32_t nativeBytesAllocated; 185 size_t nativeFootprintGCWatermark; 186 size_t nativeFootprintLimit; 187 bool nativeNeedToRunFinalization; 188 189 /* 190 * State for the GC daemon. 191 */ 192 bool hasGcThread; 193 pthread_t gcThread; 194 bool gcThreadShutdown; 195 pthread_mutex_t gcThreadMutex; 196 pthread_cond_t gcThreadCond; 197 bool gcThreadTrimNeeded; 198 }; 199 200 #define hs2heap(hs_) (&((hs_)->heaps[0])) 201 202 /* 203 * Returns true iff a soft limit is in effect for the active heap. 204 */ 205 static bool isSoftLimited(const HeapSource *hs) 206 { 207 /* softLimit will be either SIZE_MAX or the limit for the 208 * active mspace. idealSize can be greater than softLimit 209 * if there is more than one heap. If there is only one 210 * heap, a non-SIZE_MAX softLimit should always be the same 211 * as idealSize. 212 */ 213 return hs->softLimit <= hs->idealSize; 214 } 215 216 /* 217 * Returns approximately the maximum number of bytes allowed to be 218 * allocated from the active heap before a GC is forced. 219 */ 220 static size_t getAllocLimit(const HeapSource *hs) 221 { 222 if (isSoftLimited(hs)) { 223 return hs->softLimit; 224 } else { 225 return mspace_footprint_limit(hs2heap(hs)->msp); 226 } 227 } 228 229 /* 230 * Returns the current footprint of all heaps. If includeActive 231 * is false, don't count the heap at index 0. 232 */ 233 static size_t oldHeapOverhead(const HeapSource *hs, bool includeActive) 234 { 235 size_t footprint = 0; 236 size_t i; 237 238 if (includeActive) { 239 i = 0; 240 } else { 241 i = 1; 242 } 243 for (/* i = i */; i < hs->numHeaps; i++) { 244 //TODO: include size of bitmaps? If so, don't use bitsLen, listen to .max 245 footprint += mspace_footprint(hs->heaps[i].msp); 246 } 247 return footprint; 248 } 249 250 /* 251 * Returns the heap that <ptr> could have come from, or NULL 252 * if it could not have come from any heap. 253 */ 254 static Heap *ptr2heap(const HeapSource *hs, const void *ptr) 255 { 256 const size_t numHeaps = hs->numHeaps; 257 258 if (ptr != NULL) { 259 for (size_t i = 0; i < numHeaps; i++) { 260 const Heap *const heap = &hs->heaps[i]; 261 262 if ((const char *)ptr >= heap->base && (const char *)ptr < heap->limit) { 263 return (Heap *)heap; 264 } 265 } 266 } 267 return NULL; 268 } 269 270 /* 271 * Functions to update heapSource->bytesAllocated when an object 272 * is allocated or freed. mspace_usable_size() will give 273 * us a much more accurate picture of heap utilization than 274 * the requested byte sizes would. 275 * 276 * These aren't exact, and should not be treated as such. 277 */ 278 static void countAllocation(Heap *heap, const void *ptr) 279 { 280 assert(heap->bytesAllocated < mspace_footprint(heap->msp)); 281 282 heap->bytesAllocated += mspace_usable_size(ptr) + 283 HEAP_SOURCE_CHUNK_OVERHEAD; 284 heap->objectsAllocated++; 285 HeapSource* hs = gDvm.gcHeap->heapSource; 286 dvmHeapBitmapSetObjectBit(&hs->liveBits, ptr); 287 288 assert(heap->bytesAllocated < mspace_footprint(heap->msp)); 289 } 290 291 static void countFree(Heap *heap, const void *ptr, size_t *numBytes) 292 { 293 size_t delta = mspace_usable_size(ptr) + HEAP_SOURCE_CHUNK_OVERHEAD; 294 assert(delta > 0); 295 if (delta < heap->bytesAllocated) { 296 heap->bytesAllocated -= delta; 297 } else { 298 heap->bytesAllocated = 0; 299 } 300 HeapSource* hs = gDvm.gcHeap->heapSource; 301 dvmHeapBitmapClearObjectBit(&hs->liveBits, ptr); 302 if (heap->objectsAllocated > 0) { 303 heap->objectsAllocated--; 304 } 305 *numBytes += delta; 306 } 307 308 static HeapSource *gHs = NULL; 309 310 static mspace createMspace(void* begin, size_t morecoreStart, size_t startingSize) 311 { 312 // Clear errno to allow strerror on error. 313 errno = 0; 314 // Allow access to inital pages that will hold mspace. 315 mprotect(begin, morecoreStart, PROT_READ | PROT_WRITE); 316 // Create mspace using our backing storage starting at begin and with a footprint of 317 // morecoreStart. Don't use an internal dlmalloc lock. When morecoreStart bytes of memory are 318 // exhausted morecore will be called. 319 mspace msp = create_mspace_with_base(begin, morecoreStart, false /*locked*/); 320 if (msp != NULL) { 321 // Do not allow morecore requests to succeed beyond the starting size of the heap. 322 mspace_set_footprint_limit(msp, startingSize); 323 } else { 324 ALOGE("create_mspace_with_base failed %s", strerror(errno)); 325 } 326 return msp; 327 } 328 329 /* 330 * Service request from DlMalloc to increase heap size. 331 */ 332 void* dvmHeapSourceMorecore(void* mspace, intptr_t increment) 333 { 334 Heap* heap = NULL; 335 for (size_t i = 0; i < gHs->numHeaps; i++) { 336 if (gHs->heaps[i].msp == mspace) { 337 heap = &gHs->heaps[i]; 338 break; 339 } 340 } 341 if (heap == NULL) { 342 ALOGE("Failed to find heap for mspace %p", mspace); 343 dvmAbort(); 344 } 345 char* original_brk = heap->brk; 346 if (increment != 0) { 347 char* new_brk = original_brk + increment; 348 if (increment > 0) { 349 // Should never be asked to increase the allocation beyond the capacity of the space. 350 // Enforced by mspace_set_footprint_limit. 351 assert(new_brk <= heap->limit); 352 mprotect(original_brk, increment, PROT_READ | PROT_WRITE); 353 } else { 354 // Should never be asked for negative footprint (ie before base). 355 assert(original_brk + increment > heap->base); 356 // Advise we don't need the pages and protect them. 357 size_t size = -increment; 358 madvise(new_brk, size, MADV_DONTNEED); 359 mprotect(new_brk, size, PROT_NONE); 360 } 361 // Update brk. 362 heap->brk = new_brk; 363 } 364 return original_brk; 365 } 366 367 const size_t kInitialMorecoreStart = SYSTEM_PAGE_SIZE; 368 /* 369 * Add the initial heap. Returns false if the initial heap was 370 * already added to the heap source. 371 */ 372 static bool addInitialHeap(HeapSource *hs, mspace msp, size_t maximumSize) 373 { 374 assert(hs != NULL); 375 assert(msp != NULL); 376 if (hs->numHeaps != 0) { 377 return false; 378 } 379 hs->heaps[0].msp = msp; 380 hs->heaps[0].maximumSize = maximumSize; 381 hs->heaps[0].concurrentStartBytes = SIZE_MAX; 382 hs->heaps[0].base = hs->heapBase; 383 hs->heaps[0].limit = hs->heapBase + maximumSize; 384 hs->heaps[0].brk = hs->heapBase + kInitialMorecoreStart; 385 hs->numHeaps = 1; 386 return true; 387 } 388 389 /* 390 * A helper for addNewHeap(). Remap the new heap so that it will have 391 * a separate ashmem region with possibly a different name, etc. In 392 * practice, this is used to give the app heap a separate ashmem 393 * region from the zygote heap's. 394 */ 395 static bool remapNewHeap(HeapSource* hs, Heap* newHeap) 396 { 397 char* newHeapBase = newHeap->base; 398 size_t rem_size = hs->heapBase + hs->heapLength - newHeapBase; 399 munmap(newHeapBase, rem_size); 400 int fd = ashmem_create_region("dalvik-heap", rem_size); 401 if (fd == -1) { 402 ALOGE("Unable to create an ashmem region for the new heap"); 403 return false; 404 } 405 void* addr = mmap(newHeapBase, rem_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); 406 int ret = close(fd); 407 if (addr == MAP_FAILED) { 408 ALOGE("Unable to map an ashmem region for the new heap"); 409 return false; 410 } 411 if (ret == -1) { 412 ALOGE("Unable to close fd for the ashmem region for the new heap"); 413 munmap(newHeapBase, rem_size); 414 return false; 415 } 416 return true; 417 } 418 419 /* 420 * Adds an additional heap to the heap source. Returns false if there 421 * are too many heaps or insufficient free space to add another heap. 422 */ 423 static bool addNewHeap(HeapSource *hs) 424 { 425 Heap heap; 426 427 assert(hs != NULL); 428 if (hs->numHeaps >= HEAP_SOURCE_MAX_HEAP_COUNT) { 429 ALOGE("Attempt to create too many heaps (%zd >= %zd)", 430 hs->numHeaps, HEAP_SOURCE_MAX_HEAP_COUNT); 431 dvmAbort(); 432 return false; 433 } 434 435 memset(&heap, 0, sizeof(heap)); 436 437 /* 438 * Heap storage comes from a common virtual memory reservation. 439 * The new heap will start on the page after the old heap. 440 */ 441 char *base = hs->heaps[0].brk; 442 size_t overhead = base - hs->heaps[0].base; 443 assert(((size_t)hs->heaps[0].base & (SYSTEM_PAGE_SIZE - 1)) == 0); 444 445 if (overhead + hs->minFree >= hs->maximumSize) { 446 LOGE_HEAP("No room to create any more heaps " 447 "(%zd overhead, %zd max)", 448 overhead, hs->maximumSize); 449 return false; 450 } 451 size_t morecoreStart = SYSTEM_PAGE_SIZE; 452 heap.maximumSize = hs->growthLimit - overhead; 453 heap.concurrentStartBytes = hs->minFree - CONCURRENT_START; 454 heap.base = base; 455 heap.limit = heap.base + heap.maximumSize; 456 heap.brk = heap.base + morecoreStart; 457 if (!remapNewHeap(hs, &heap)) { 458 return false; 459 } 460 heap.msp = createMspace(base, morecoreStart, hs->minFree); 461 if (heap.msp == NULL) { 462 return false; 463 } 464 465 /* Don't let the soon-to-be-old heap grow any further. 466 */ 467 hs->heaps[0].maximumSize = overhead; 468 hs->heaps[0].limit = base; 469 mspace_set_footprint_limit(hs->heaps[0].msp, overhead); 470 471 /* Put the new heap in the list, at heaps[0]. 472 * Shift existing heaps down. 473 */ 474 memmove(&hs->heaps[1], &hs->heaps[0], hs->numHeaps * sizeof(hs->heaps[0])); 475 hs->heaps[0] = heap; 476 hs->numHeaps++; 477 478 return true; 479 } 480 481 /* 482 * The garbage collection daemon. Initiates a concurrent collection 483 * when signaled. Also periodically trims the heaps when a few seconds 484 * have elapsed since the last concurrent GC. 485 */ 486 static void *gcDaemonThread(void* arg) 487 { 488 dvmChangeStatus(NULL, THREAD_VMWAIT); 489 dvmLockMutex(&gHs->gcThreadMutex); 490 while (gHs->gcThreadShutdown != true) { 491 bool trim = false; 492 if (gHs->gcThreadTrimNeeded) { 493 int result = dvmRelativeCondWait(&gHs->gcThreadCond, &gHs->gcThreadMutex, 494 HEAP_TRIM_IDLE_TIME_MS, 0); 495 if (result == ETIMEDOUT) { 496 /* Timed out waiting for a GC request, schedule a heap trim. */ 497 trim = true; 498 } 499 } else { 500 dvmWaitCond(&gHs->gcThreadCond, &gHs->gcThreadMutex); 501 } 502 503 // Many JDWP requests cause allocation. We can't take the heap lock and wait to 504 // transition to runnable so we can start a GC if a debugger is connected, because 505 // we don't know that the JDWP thread isn't about to allocate and require the 506 // heap lock itself, leading to deadlock. http://b/8191824. 507 if (gDvm.debuggerConnected) { 508 continue; 509 } 510 511 dvmLockHeap(); 512 /* 513 * Another thread may have started a concurrent garbage 514 * collection before we were scheduled. Check for this 515 * condition before proceeding. 516 */ 517 if (!gDvm.gcHeap->gcRunning) { 518 dvmChangeStatus(NULL, THREAD_RUNNING); 519 if (trim) { 520 trimHeaps(); 521 gHs->gcThreadTrimNeeded = false; 522 } else { 523 dvmCollectGarbageInternal(GC_CONCURRENT); 524 gHs->gcThreadTrimNeeded = true; 525 } 526 dvmChangeStatus(NULL, THREAD_VMWAIT); 527 } 528 dvmUnlockHeap(); 529 } 530 dvmChangeStatus(NULL, THREAD_RUNNING); 531 return NULL; 532 } 533 534 static bool gcDaemonStartup() 535 { 536 dvmInitMutex(&gHs->gcThreadMutex); 537 pthread_cond_init(&gHs->gcThreadCond, NULL); 538 gHs->gcThreadShutdown = false; 539 gHs->hasGcThread = dvmCreateInternalThread(&gHs->gcThread, "GC", 540 gcDaemonThread, NULL); 541 return gHs->hasGcThread; 542 } 543 544 static void gcDaemonShutdown() 545 { 546 if (gHs->hasGcThread) { 547 dvmLockMutex(&gHs->gcThreadMutex); 548 gHs->gcThreadShutdown = true; 549 dvmSignalCond(&gHs->gcThreadCond); 550 dvmUnlockMutex(&gHs->gcThreadMutex); 551 pthread_join(gHs->gcThread, NULL); 552 } 553 } 554 555 /* 556 * Create a stack big enough for the worst possible case, where the 557 * heap is perfectly full of the smallest object. 558 * TODO: be better about memory usage; use a smaller stack with 559 * overflow detection and recovery. 560 */ 561 static bool allocMarkStack(GcMarkStack *stack, size_t maximumSize) 562 { 563 const char *name = "dalvik-mark-stack"; 564 void *addr; 565 566 assert(stack != NULL); 567 stack->length = maximumSize * sizeof(Object*) / 568 (sizeof(Object) + HEAP_SOURCE_CHUNK_OVERHEAD); 569 addr = dvmAllocRegion(stack->length, PROT_READ | PROT_WRITE, name); 570 if (addr == NULL) { 571 return false; 572 } 573 stack->base = (const Object **)addr; 574 stack->limit = (const Object **)((char *)addr + stack->length); 575 stack->top = NULL; 576 madvise(stack->base, stack->length, MADV_DONTNEED); 577 return true; 578 } 579 580 static void freeMarkStack(GcMarkStack *stack) 581 { 582 assert(stack != NULL); 583 munmap(stack->base, stack->length); 584 memset(stack, 0, sizeof(*stack)); 585 } 586 587 /* 588 * Initializes the heap source; must be called before any other 589 * dvmHeapSource*() functions. Returns a GcHeap structure 590 * allocated from the heap source. 591 */ 592 GcHeap* dvmHeapSourceStartup(size_t startSize, size_t maximumSize, 593 size_t growthLimit) 594 { 595 GcHeap *gcHeap; 596 HeapSource *hs; 597 mspace msp; 598 size_t length; 599 void *base; 600 601 assert(gHs == NULL); 602 603 if (!(startSize <= growthLimit && growthLimit <= maximumSize)) { 604 ALOGE("Bad heap size parameters (start=%zd, max=%zd, limit=%zd)", 605 startSize, maximumSize, growthLimit); 606 return NULL; 607 } 608 609 /* 610 * Allocate a contiguous region of virtual memory to subdivided 611 * among the heaps managed by the garbage collector. 612 */ 613 length = ALIGN_UP_TO_PAGE_SIZE(maximumSize); 614 base = dvmAllocRegion(length, PROT_NONE, gDvm.zygote ? "dalvik-zygote" : "dalvik-heap"); 615 if (base == NULL) { 616 return NULL; 617 } 618 619 /* Create an unlocked dlmalloc mspace to use as 620 * a heap source. 621 */ 622 msp = createMspace(base, kInitialMorecoreStart, startSize); 623 if (msp == NULL) { 624 goto fail; 625 } 626 627 gcHeap = (GcHeap *)calloc(1, sizeof(*gcHeap)); 628 if (gcHeap == NULL) { 629 LOGE_HEAP("Can't allocate heap descriptor"); 630 goto fail; 631 } 632 633 hs = (HeapSource *)calloc(1, sizeof(*hs)); 634 if (hs == NULL) { 635 LOGE_HEAP("Can't allocate heap source"); 636 free(gcHeap); 637 goto fail; 638 } 639 640 hs->targetUtilization = gDvm.heapTargetUtilization * HEAP_UTILIZATION_MAX; 641 hs->minFree = gDvm.heapMinFree; 642 hs->maxFree = gDvm.heapMaxFree; 643 hs->startSize = startSize; 644 hs->maximumSize = maximumSize; 645 hs->growthLimit = growthLimit; 646 hs->idealSize = startSize; 647 hs->softLimit = SIZE_MAX; // no soft limit at first 648 hs->numHeaps = 0; 649 hs->sawZygote = gDvm.zygote; 650 hs->nativeBytesAllocated = 0; 651 hs->nativeFootprintGCWatermark = startSize; 652 hs->nativeFootprintLimit = startSize * 2; 653 hs->nativeNeedToRunFinalization = false; 654 hs->hasGcThread = false; 655 hs->heapBase = (char *)base; 656 hs->heapLength = length; 657 658 if (hs->maxFree > hs->maximumSize) { 659 hs->maxFree = hs->maximumSize; 660 } 661 if (hs->minFree < CONCURRENT_START) { 662 hs->minFree = CONCURRENT_START; 663 } else if (hs->minFree > hs->maxFree) { 664 hs->minFree = hs->maxFree; 665 } 666 667 if (!addInitialHeap(hs, msp, growthLimit)) { 668 LOGE_HEAP("Can't add initial heap"); 669 goto fail; 670 } 671 if (!dvmHeapBitmapInit(&hs->liveBits, base, length, "dalvik-bitmap-1")) { 672 LOGE_HEAP("Can't create liveBits"); 673 goto fail; 674 } 675 if (!dvmHeapBitmapInit(&hs->markBits, base, length, "dalvik-bitmap-2")) { 676 LOGE_HEAP("Can't create markBits"); 677 dvmHeapBitmapDelete(&hs->liveBits); 678 goto fail; 679 } 680 if (!allocMarkStack(&gcHeap->markContext.stack, hs->maximumSize)) { 681 ALOGE("Can't create markStack"); 682 dvmHeapBitmapDelete(&hs->markBits); 683 dvmHeapBitmapDelete(&hs->liveBits); 684 goto fail; 685 } 686 gcHeap->markContext.bitmap = &hs->markBits; 687 gcHeap->heapSource = hs; 688 689 gHs = hs; 690 return gcHeap; 691 692 fail: 693 munmap(base, length); 694 return NULL; 695 } 696 697 bool dvmHeapSourceStartupAfterZygote() 698 { 699 return gDvm.concurrentMarkSweep ? gcDaemonStartup() : true; 700 } 701 702 /* 703 * This is called while in zygote mode, right before we fork() for the 704 * first time. We create a heap for all future zygote process allocations, 705 * in an attempt to avoid touching pages in the zygote heap. (This would 706 * probably be unnecessary if we had a compacting GC -- the source of our 707 * troubles is small allocations filling in the gaps from larger ones.) 708 */ 709 bool dvmHeapSourceStartupBeforeFork() 710 { 711 HeapSource *hs = gHs; // use a local to avoid the implicit "volatile" 712 713 HS_BOILERPLATE(); 714 715 assert(gDvm.zygote); 716 717 if (!gDvm.newZygoteHeapAllocated) { 718 /* Ensure heaps are trimmed to minimize footprint pre-fork. 719 */ 720 trimHeaps(); 721 /* Create a new heap for post-fork zygote allocations. We only 722 * try once, even if it fails. 723 */ 724 ALOGV("Splitting out new zygote heap"); 725 gDvm.newZygoteHeapAllocated = true; 726 return addNewHeap(hs); 727 } 728 return true; 729 } 730 731 void dvmHeapSourceThreadShutdown() 732 { 733 if (gDvm.gcHeap != NULL && gDvm.concurrentMarkSweep) { 734 gcDaemonShutdown(); 735 } 736 } 737 738 /* 739 * Tears down the entire GcHeap structure and all of the substructures 740 * attached to it. This call has the side effect of setting the given 741 * gcHeap pointer and gHs to NULL. 742 */ 743 void dvmHeapSourceShutdown(GcHeap **gcHeap) 744 { 745 assert(gcHeap != NULL); 746 if (*gcHeap != NULL && (*gcHeap)->heapSource != NULL) { 747 HeapSource *hs = (*gcHeap)->heapSource; 748 dvmHeapBitmapDelete(&hs->liveBits); 749 dvmHeapBitmapDelete(&hs->markBits); 750 freeMarkStack(&(*gcHeap)->markContext.stack); 751 munmap(hs->heapBase, hs->heapLength); 752 free(hs); 753 gHs = NULL; 754 free(*gcHeap); 755 *gcHeap = NULL; 756 } 757 } 758 759 /* 760 * Gets the begining of the allocation for the HeapSource. 761 */ 762 void *dvmHeapSourceGetBase() 763 { 764 return gHs->heapBase; 765 } 766 767 /* 768 * Returns a high water mark, between base and limit all objects must have been 769 * allocated. 770 */ 771 void *dvmHeapSourceGetLimit() 772 { 773 HeapSource *hs = gHs; 774 void *max_brk = hs->heaps[0].brk; 775 776 #ifndef NDEBUG 777 for (size_t i = 1; i < hs->numHeaps; i++) { 778 Heap *const heap = &hs->heaps[i]; 779 void *heap_brk = heap->brk; 780 assert (max_brk > heap_brk); 781 } 782 #endif 783 return max_brk; 784 } 785 786 /* 787 * Returns the requested value. If the per-heap stats are requested, fill 788 * them as well. 789 * 790 * Caller must hold the heap lock. 791 */ 792 size_t dvmHeapSourceGetValue(HeapSourceValueSpec spec, size_t perHeapStats[], 793 size_t arrayLen) 794 { 795 HeapSource *hs = gHs; 796 size_t value = 0; 797 size_t total = 0; 798 799 HS_BOILERPLATE(); 800 801 assert(arrayLen >= hs->numHeaps || perHeapStats == NULL); 802 for (size_t i = 0; i < hs->numHeaps; i++) { 803 Heap *const heap = &hs->heaps[i]; 804 805 switch (spec) { 806 case HS_FOOTPRINT: 807 value = heap->brk - heap->base; 808 assert(value == mspace_footprint(heap->msp)); 809 break; 810 case HS_ALLOWED_FOOTPRINT: 811 value = mspace_footprint_limit(heap->msp); 812 break; 813 case HS_BYTES_ALLOCATED: 814 value = heap->bytesAllocated; 815 break; 816 case HS_OBJECTS_ALLOCATED: 817 value = heap->objectsAllocated; 818 break; 819 default: 820 // quiet gcc 821 break; 822 } 823 if (perHeapStats) { 824 perHeapStats[i] = value; 825 } 826 total += value; 827 } 828 return total; 829 } 830 831 void dvmHeapSourceGetRegions(uintptr_t *base, uintptr_t *max, size_t numHeaps) 832 { 833 HeapSource *hs = gHs; 834 835 HS_BOILERPLATE(); 836 837 assert(numHeaps <= hs->numHeaps); 838 for (size_t i = 0; i < numHeaps; ++i) { 839 base[i] = (uintptr_t)hs->heaps[i].base; 840 max[i] = MIN((uintptr_t)hs->heaps[i].limit - 1, hs->markBits.max); 841 } 842 } 843 844 /* 845 * Get the bitmap representing all live objects. 846 */ 847 HeapBitmap *dvmHeapSourceGetLiveBits() 848 { 849 HS_BOILERPLATE(); 850 851 return &gHs->liveBits; 852 } 853 854 /* 855 * Get the bitmap representing all marked objects. 856 */ 857 HeapBitmap *dvmHeapSourceGetMarkBits() 858 { 859 HS_BOILERPLATE(); 860 861 return &gHs->markBits; 862 } 863 864 void dvmHeapSourceSwapBitmaps() 865 { 866 HeapBitmap tmp = gHs->liveBits; 867 gHs->liveBits = gHs->markBits; 868 gHs->markBits = tmp; 869 } 870 871 void dvmHeapSourceZeroMarkBitmap() 872 { 873 HS_BOILERPLATE(); 874 875 dvmHeapBitmapZero(&gHs->markBits); 876 } 877 878 void dvmMarkImmuneObjects(const char *immuneLimit) 879 { 880 /* 881 * Copy the contents of the live bit vector for immune object 882 * range into the mark bit vector. 883 */ 884 /* The only values generated by dvmHeapSourceGetImmuneLimit() */ 885 assert(immuneLimit == gHs->heaps[0].base || 886 immuneLimit == NULL); 887 assert(gHs->liveBits.base == gHs->markBits.base); 888 assert(gHs->liveBits.bitsLen == gHs->markBits.bitsLen); 889 /* heap[0] is never immune */ 890 assert(gHs->heaps[0].base >= immuneLimit); 891 assert(gHs->heaps[0].limit > immuneLimit); 892 893 for (size_t i = 1; i < gHs->numHeaps; ++i) { 894 if (gHs->heaps[i].base < immuneLimit) { 895 assert(gHs->heaps[i].limit <= immuneLimit); 896 /* Compute the number of words to copy in the bitmap. */ 897 size_t index = HB_OFFSET_TO_INDEX( 898 (uintptr_t)gHs->heaps[i].base - gHs->liveBits.base); 899 /* Compute the starting offset in the live and mark bits. */ 900 char *src = (char *)(gHs->liveBits.bits + index); 901 char *dst = (char *)(gHs->markBits.bits + index); 902 /* Compute the number of bytes of the live bitmap to copy. */ 903 size_t length = HB_OFFSET_TO_BYTE_INDEX( 904 gHs->heaps[i].limit - gHs->heaps[i].base); 905 /* Do the copy. */ 906 memcpy(dst, src, length); 907 /* Make sure max points to the address of the highest set bit. */ 908 if (gHs->markBits.max < (uintptr_t)gHs->heaps[i].limit) { 909 gHs->markBits.max = (uintptr_t)gHs->heaps[i].limit; 910 } 911 } 912 } 913 } 914 915 /* 916 * Allocates <n> bytes of zeroed data. 917 */ 918 void* dvmHeapSourceAlloc(size_t n) 919 { 920 HS_BOILERPLATE(); 921 922 HeapSource *hs = gHs; 923 Heap* heap = hs2heap(hs); 924 if (heap->bytesAllocated + n > hs->softLimit) { 925 /* 926 * This allocation would push us over the soft limit; act as 927 * if the heap is full. 928 */ 929 LOGV_HEAP("softLimit of %zd.%03zdMB hit for %zd-byte allocation", 930 FRACTIONAL_MB(hs->softLimit), n); 931 return NULL; 932 } 933 void* ptr; 934 if (gDvm.lowMemoryMode) { 935 /* This is only necessary because mspace_calloc always memsets the 936 * allocated memory to 0. This is bad for memory usage since it leads 937 * to dirty zero pages. If low memory mode is enabled, we use 938 * mspace_malloc which doesn't memset the allocated memory and madvise 939 * the page aligned region back to the kernel. 940 */ 941 ptr = mspace_malloc(heap->msp, n); 942 if (ptr == NULL) { 943 return NULL; 944 } 945 uintptr_t zero_begin = (uintptr_t)ptr; 946 uintptr_t zero_end = (uintptr_t)ptr + n; 947 /* Calculate the page aligned region. 948 */ 949 uintptr_t begin = ALIGN_UP_TO_PAGE_SIZE(zero_begin); 950 uintptr_t end = zero_end & ~(uintptr_t)(SYSTEM_PAGE_SIZE - 1); 951 /* If our allocation spans more than one page, we attempt to madvise. 952 */ 953 if (begin < end) { 954 /* madvise the page aligned region to kernel. 955 */ 956 madvise((void*)begin, end - begin, MADV_DONTNEED); 957 /* Zero the region after the page aligned region. 958 */ 959 memset((void*)end, 0, zero_end - end); 960 /* Zero out the region before the page aligned region. 961 */ 962 zero_end = begin; 963 } 964 memset((void*)zero_begin, 0, zero_end - zero_begin); 965 } else { 966 ptr = mspace_calloc(heap->msp, 1, n); 967 if (ptr == NULL) { 968 return NULL; 969 } 970 } 971 972 countAllocation(heap, ptr); 973 /* 974 * Check to see if a concurrent GC should be initiated. 975 */ 976 if (gDvm.gcHeap->gcRunning || !hs->hasGcThread) { 977 /* 978 * The garbage collector thread is already running or has yet 979 * to be started. Do nothing. 980 */ 981 return ptr; 982 } 983 if (heap->bytesAllocated > heap->concurrentStartBytes) { 984 /* 985 * We have exceeded the allocation threshold. Wake up the 986 * garbage collector. 987 */ 988 dvmSignalCond(&gHs->gcThreadCond); 989 } 990 return ptr; 991 } 992 993 /* Remove any hard limits, try to allocate, and shrink back down. 994 * Last resort when trying to allocate an object. 995 */ 996 static void* heapAllocAndGrow(HeapSource *hs, Heap *heap, size_t n) 997 { 998 /* Grow as much as possible, but don't let the real footprint 999 * go over the absolute max. 1000 */ 1001 size_t max = heap->maximumSize; 1002 1003 mspace_set_footprint_limit(heap->msp, max); 1004 void* ptr = dvmHeapSourceAlloc(n); 1005 1006 /* Shrink back down as small as possible. Our caller may 1007 * readjust max_allowed to a more appropriate value. 1008 */ 1009 mspace_set_footprint_limit(heap->msp, 1010 mspace_footprint(heap->msp)); 1011 return ptr; 1012 } 1013 1014 /* 1015 * Allocates <n> bytes of zeroed data, growing as much as possible 1016 * if necessary. 1017 */ 1018 void* dvmHeapSourceAllocAndGrow(size_t n) 1019 { 1020 HS_BOILERPLATE(); 1021 1022 HeapSource *hs = gHs; 1023 Heap* heap = hs2heap(hs); 1024 void* ptr = dvmHeapSourceAlloc(n); 1025 if (ptr != NULL) { 1026 return ptr; 1027 } 1028 1029 size_t oldIdealSize = hs->idealSize; 1030 if (isSoftLimited(hs)) { 1031 /* We're soft-limited. Try removing the soft limit to 1032 * see if we can allocate without actually growing. 1033 */ 1034 hs->softLimit = SIZE_MAX; 1035 ptr = dvmHeapSourceAlloc(n); 1036 if (ptr != NULL) { 1037 /* Removing the soft limit worked; fix things up to 1038 * reflect the new effective ideal size. 1039 */ 1040 snapIdealFootprint(); 1041 return ptr; 1042 } 1043 // softLimit intentionally left at SIZE_MAX. 1044 } 1045 1046 /* We're not soft-limited. Grow the heap to satisfy the request. 1047 * If this call fails, no footprints will have changed. 1048 */ 1049 ptr = heapAllocAndGrow(hs, heap, n); 1050 if (ptr != NULL) { 1051 /* The allocation succeeded. Fix up the ideal size to 1052 * reflect any footprint modifications that had to happen. 1053 */ 1054 snapIdealFootprint(); 1055 } else { 1056 /* We just couldn't do it. Restore the original ideal size, 1057 * fixing up softLimit if necessary. 1058 */ 1059 setIdealFootprint(oldIdealSize); 1060 } 1061 return ptr; 1062 } 1063 1064 /* 1065 * Frees the first numPtrs objects in the ptrs list and returns the 1066 * amount of reclaimed storage. The list must contain addresses all in 1067 * the same mspace, and must be in increasing order. This implies that 1068 * there are no duplicates, and no entries are NULL. 1069 */ 1070 size_t dvmHeapSourceFreeList(size_t numPtrs, void **ptrs) 1071 { 1072 HS_BOILERPLATE(); 1073 1074 if (numPtrs == 0) { 1075 return 0; 1076 } 1077 1078 assert(ptrs != NULL); 1079 assert(*ptrs != NULL); 1080 Heap* heap = ptr2heap(gHs, *ptrs); 1081 size_t numBytes = 0; 1082 if (heap != NULL) { 1083 mspace msp = heap->msp; 1084 // Calling mspace_free on shared heaps disrupts sharing too 1085 // much. For heap[0] -- the 'active heap' -- we call 1086 // mspace_free, but on the other heaps we only do some 1087 // accounting. 1088 if (heap == gHs->heaps) { 1089 // Count freed objects. 1090 for (size_t i = 0; i < numPtrs; i++) { 1091 assert(ptrs[i] != NULL); 1092 assert(ptr2heap(gHs, ptrs[i]) == heap); 1093 countFree(heap, ptrs[i], &numBytes); 1094 } 1095 // Bulk free ptrs. 1096 mspace_bulk_free(msp, ptrs, numPtrs); 1097 } else { 1098 // This is not an 'active heap'. Only do the accounting. 1099 for (size_t i = 0; i < numPtrs; i++) { 1100 assert(ptrs[i] != NULL); 1101 assert(ptr2heap(gHs, ptrs[i]) == heap); 1102 countFree(heap, ptrs[i], &numBytes); 1103 } 1104 } 1105 } 1106 return numBytes; 1107 } 1108 1109 /* 1110 * Returns true iff <ptr> is in the heap source. 1111 */ 1112 bool dvmHeapSourceContainsAddress(const void *ptr) 1113 { 1114 HS_BOILERPLATE(); 1115 1116 return (dvmHeapSourceGetBase() <= ptr) && (ptr <= dvmHeapSourceGetLimit()); 1117 } 1118 1119 /* 1120 * Returns true iff <ptr> was allocated from the heap source. 1121 */ 1122 bool dvmHeapSourceContains(const void *ptr) 1123 { 1124 HS_BOILERPLATE(); 1125 1126 if (dvmHeapSourceContainsAddress(ptr)) { 1127 return dvmHeapBitmapIsObjectBitSet(&gHs->liveBits, ptr) != 0; 1128 } 1129 return false; 1130 } 1131 1132 bool dvmIsZygoteObject(const Object* obj) 1133 { 1134 HeapSource *hs = gHs; 1135 1136 HS_BOILERPLATE(); 1137 1138 if (dvmHeapSourceContains(obj) && hs->sawZygote) { 1139 Heap *heap = ptr2heap(hs, obj); 1140 if (heap != NULL) { 1141 /* If the object is not in the active heap, we assume that 1142 * it was allocated as part of zygote. 1143 */ 1144 return heap != hs->heaps; 1145 } 1146 } 1147 /* The pointer is outside of any known heap, or we are not 1148 * running in zygote mode. 1149 */ 1150 return false; 1151 } 1152 1153 /* 1154 * Returns the number of usable bytes in an allocated chunk; the size 1155 * may be larger than the size passed to dvmHeapSourceAlloc(). 1156 */ 1157 size_t dvmHeapSourceChunkSize(const void *ptr) 1158 { 1159 HS_BOILERPLATE(); 1160 1161 Heap* heap = ptr2heap(gHs, ptr); 1162 if (heap != NULL) { 1163 return mspace_usable_size(ptr); 1164 } 1165 return 0; 1166 } 1167 1168 /* 1169 * Returns the number of bytes that the heap source has allocated 1170 * from the system using sbrk/mmap, etc. 1171 * 1172 * Caller must hold the heap lock. 1173 */ 1174 size_t dvmHeapSourceFootprint() 1175 { 1176 HS_BOILERPLATE(); 1177 1178 //TODO: include size of bitmaps? 1179 return oldHeapOverhead(gHs, true); 1180 } 1181 1182 static size_t getMaximumSize(const HeapSource *hs) 1183 { 1184 return hs->growthLimit; 1185 } 1186 1187 /* 1188 * Returns the current maximum size of the heap source respecting any 1189 * growth limits. 1190 */ 1191 size_t dvmHeapSourceGetMaximumSize() 1192 { 1193 HS_BOILERPLATE(); 1194 return getMaximumSize(gHs); 1195 } 1196 1197 /* 1198 * Removes any growth limits. Allows the user to allocate up to the 1199 * maximum heap size. 1200 */ 1201 void dvmClearGrowthLimit() 1202 { 1203 HS_BOILERPLATE(); 1204 dvmLockHeap(); 1205 dvmWaitForConcurrentGcToComplete(); 1206 gDvm.gcHeap->cardTableLength = gDvm.gcHeap->cardTableMaxLength; 1207 gHs->growthLimit = gHs->maximumSize; 1208 size_t overhead = oldHeapOverhead(gHs, false); 1209 gHs->heaps[0].maximumSize = gHs->maximumSize - overhead; 1210 gHs->heaps[0].limit = gHs->heaps[0].base + gHs->heaps[0].maximumSize; 1211 dvmUnlockHeap(); 1212 } 1213 1214 /* 1215 * Return the real bytes used by old heaps plus the soft usage of the 1216 * current heap. When a soft limit is in effect, this is effectively 1217 * what it's compared against (though, in practice, it only looks at 1218 * the current heap). 1219 */ 1220 static size_t getSoftFootprint(bool includeActive) 1221 { 1222 HS_BOILERPLATE(); 1223 1224 HeapSource *hs = gHs; 1225 size_t ret = oldHeapOverhead(hs, false); 1226 if (includeActive) { 1227 ret += hs->heaps[0].bytesAllocated; 1228 } 1229 1230 return ret; 1231 } 1232 1233 /* 1234 * Gets the maximum number of bytes that the heap source is allowed 1235 * to allocate from the system. 1236 */ 1237 size_t dvmHeapSourceGetIdealFootprint() 1238 { 1239 HeapSource *hs = gHs; 1240 1241 HS_BOILERPLATE(); 1242 1243 return hs->idealSize; 1244 } 1245 1246 /* 1247 * Sets the soft limit, handling any necessary changes to the allowed 1248 * footprint of the active heap. 1249 */ 1250 static void setSoftLimit(HeapSource *hs, size_t softLimit) 1251 { 1252 /* Compare against the actual footprint, rather than the 1253 * max_allowed, because the heap may not have grown all the 1254 * way to the allowed size yet. 1255 */ 1256 mspace msp = hs->heaps[0].msp; 1257 size_t currentHeapSize = mspace_footprint(msp); 1258 if (softLimit < currentHeapSize) { 1259 /* Don't let the heap grow any more, and impose a soft limit. 1260 */ 1261 mspace_set_footprint_limit(msp, currentHeapSize); 1262 hs->softLimit = softLimit; 1263 } else { 1264 /* Let the heap grow to the requested max, and remove any 1265 * soft limit, if set. 1266 */ 1267 mspace_set_footprint_limit(msp, softLimit); 1268 hs->softLimit = SIZE_MAX; 1269 } 1270 } 1271 1272 /* 1273 * Sets the maximum number of bytes that the heap source is allowed 1274 * to allocate from the system. Clamps to the appropriate maximum 1275 * value. 1276 */ 1277 static void setIdealFootprint(size_t max) 1278 { 1279 HS_BOILERPLATE(); 1280 1281 HeapSource *hs = gHs; 1282 size_t maximumSize = getMaximumSize(hs); 1283 if (max > maximumSize) { 1284 LOGI_HEAP("Clamp target GC heap from %zd.%03zdMB to %u.%03uMB", 1285 FRACTIONAL_MB(max), 1286 FRACTIONAL_MB(maximumSize)); 1287 max = maximumSize; 1288 } 1289 1290 /* Convert max into a size that applies to the active heap. 1291 * Old heaps will count against the ideal size. 1292 */ 1293 size_t overhead = getSoftFootprint(false); 1294 size_t activeMax; 1295 if (overhead < max) { 1296 activeMax = max - overhead; 1297 } else { 1298 activeMax = 0; 1299 } 1300 1301 setSoftLimit(hs, activeMax); 1302 hs->idealSize = max; 1303 } 1304 1305 /* 1306 * Make the ideal footprint equal to the current footprint. 1307 */ 1308 static void snapIdealFootprint() 1309 { 1310 HS_BOILERPLATE(); 1311 1312 setIdealFootprint(getSoftFootprint(true)); 1313 } 1314 1315 /* 1316 * Gets the current ideal heap utilization, represented as a number 1317 * between zero and one. 1318 */ 1319 float dvmGetTargetHeapUtilization() 1320 { 1321 HeapSource *hs = gHs; 1322 1323 HS_BOILERPLATE(); 1324 1325 return (float)hs->targetUtilization / (float)HEAP_UTILIZATION_MAX; 1326 } 1327 1328 /* 1329 * Sets the new ideal heap utilization, represented as a number 1330 * between zero and one. 1331 */ 1332 void dvmSetTargetHeapUtilization(float newTarget) 1333 { 1334 HeapSource *hs = gHs; 1335 1336 HS_BOILERPLATE(); 1337 1338 /* Clamp it to a reasonable range. 1339 */ 1340 // TODO: This may need some tuning. 1341 if (newTarget < 0.2) { 1342 newTarget = 0.2; 1343 } else if (newTarget > 0.8) { 1344 newTarget = 0.8; 1345 } 1346 1347 hs->targetUtilization = 1348 (size_t)(newTarget * (float)HEAP_UTILIZATION_MAX); 1349 ALOGV("Set heap target utilization to %zd/%d (%f)", 1350 hs->targetUtilization, HEAP_UTILIZATION_MAX, newTarget); 1351 } 1352 1353 /* 1354 * Given the size of a live set, returns the ideal heap size given 1355 * the current target utilization and MIN/MAX values. 1356 */ 1357 static size_t getUtilizationTarget(const HeapSource* hs, size_t liveSize) 1358 { 1359 /* Use the current target utilization ratio to determine the 1360 * ideal heap size based on the size of the live set. 1361 */ 1362 size_t targetSize = (liveSize / hs->targetUtilization) * HEAP_UTILIZATION_MAX; 1363 1364 /* Cap the amount of free space, though, so we don't end up 1365 * with, e.g., 8MB of free space when the live set size hits 8MB. 1366 */ 1367 if (targetSize > liveSize + hs->maxFree) { 1368 targetSize = liveSize + hs->maxFree; 1369 } else if (targetSize < liveSize + hs->minFree) { 1370 targetSize = liveSize + hs->minFree; 1371 } 1372 return targetSize; 1373 } 1374 1375 /* 1376 * Given the current contents of the active heap, increase the allowed 1377 * heap footprint to match the target utilization ratio. This 1378 * should only be called immediately after a full mark/sweep. 1379 */ 1380 void dvmHeapSourceGrowForUtilization() 1381 { 1382 HS_BOILERPLATE(); 1383 1384 HeapSource *hs = gHs; 1385 Heap* heap = hs2heap(hs); 1386 1387 /* Use the current target utilization ratio to determine the 1388 * ideal heap size based on the size of the live set. 1389 * Note that only the active heap plays any part in this. 1390 * 1391 * Avoid letting the old heaps influence the target free size, 1392 * because they may be full of objects that aren't actually 1393 * in the working set. Just look at the allocated size of 1394 * the current heap. 1395 */ 1396 size_t currentHeapUsed = heap->bytesAllocated; 1397 size_t targetHeapSize = getUtilizationTarget(hs, currentHeapUsed); 1398 1399 /* The ideal size includes the old heaps; add overhead so that 1400 * it can be immediately subtracted again in setIdealFootprint(). 1401 * If the target heap size would exceed the max, setIdealFootprint() 1402 * will clamp it to a legal value. 1403 */ 1404 size_t overhead = getSoftFootprint(false); 1405 setIdealFootprint(targetHeapSize + overhead); 1406 1407 size_t freeBytes = getAllocLimit(hs); 1408 if (freeBytes < CONCURRENT_MIN_FREE) { 1409 /* Not enough free memory to allow a concurrent GC. */ 1410 heap->concurrentStartBytes = SIZE_MAX; 1411 } else { 1412 heap->concurrentStartBytes = freeBytes - CONCURRENT_START; 1413 } 1414 1415 /* Mark that we need to run finalizers and update the native watermarks 1416 * next time we attempt to register a native allocation. 1417 */ 1418 gHs->nativeNeedToRunFinalization = true; 1419 } 1420 1421 /* 1422 * Return free pages to the system. 1423 * TODO: move this somewhere else, especially the native heap part. 1424 */ 1425 static void releasePagesInRange(void* start, void* end, size_t used_bytes, 1426 void* releasedBytes) 1427 { 1428 if (used_bytes == 0) { 1429 /* 1430 * We have a range of memory we can try to madvise() 1431 * back. Linux requires that the madvise() start address is 1432 * page-aligned. We also align the end address. 1433 */ 1434 start = (void *)ALIGN_UP_TO_PAGE_SIZE(start); 1435 end = (void *)((size_t)end & ~(SYSTEM_PAGE_SIZE - 1)); 1436 if (end > start) { 1437 size_t length = (char *)end - (char *)start; 1438 madvise(start, length, MADV_DONTNEED); 1439 *(size_t *)releasedBytes += length; 1440 } 1441 } 1442 } 1443 1444 /* 1445 * Return unused memory to the system if possible. 1446 */ 1447 static void trimHeaps() 1448 { 1449 HS_BOILERPLATE(); 1450 1451 HeapSource *hs = gHs; 1452 size_t heapBytes = 0; 1453 for (size_t i = 0; i < hs->numHeaps; i++) { 1454 Heap *heap = &hs->heaps[i]; 1455 1456 /* Return the wilderness chunk to the system. */ 1457 mspace_trim(heap->msp, 0); 1458 1459 /* Return any whole free pages to the system. */ 1460 mspace_inspect_all(heap->msp, releasePagesInRange, &heapBytes); 1461 } 1462 1463 /* Same for the native heap. */ 1464 dlmalloc_trim(0); 1465 size_t nativeBytes = 0; 1466 dlmalloc_inspect_all(releasePagesInRange, &nativeBytes); 1467 1468 LOGD_HEAP("madvised %zd (GC) + %zd (native) = %zd total bytes", 1469 heapBytes, nativeBytes, heapBytes + nativeBytes); 1470 } 1471 1472 /* 1473 * Walks over the heap source and passes every allocated and 1474 * free chunk to the callback. 1475 */ 1476 void dvmHeapSourceWalk(void(*callback)(void* start, void* end, 1477 size_t used_bytes, void* arg), 1478 void *arg) 1479 { 1480 HS_BOILERPLATE(); 1481 1482 /* Walk the heaps from oldest to newest. 1483 */ 1484 //TODO: do this in address order 1485 HeapSource *hs = gHs; 1486 for (size_t i = hs->numHeaps; i > 0; --i) { 1487 mspace_inspect_all(hs->heaps[i-1].msp, callback, arg); 1488 callback(NULL, NULL, 0, arg); // Indicate end of a heap. 1489 } 1490 } 1491 1492 /* 1493 * Gets the number of heaps available in the heap source. 1494 * 1495 * Caller must hold the heap lock, because gHs caches a field 1496 * in gDvm.gcHeap. 1497 */ 1498 size_t dvmHeapSourceGetNumHeaps() 1499 { 1500 HS_BOILERPLATE(); 1501 1502 return gHs->numHeaps; 1503 } 1504 1505 void *dvmHeapSourceGetImmuneLimit(bool isPartial) 1506 { 1507 if (isPartial) { 1508 return hs2heap(gHs)->base; 1509 } else { 1510 return NULL; 1511 } 1512 } 1513 1514 static void dvmHeapSourceUpdateMaxNativeFootprint() 1515 { 1516 /* Use the current target utilization ratio to determine the new native GC 1517 * watermarks. 1518 */ 1519 size_t nativeSize = gHs->nativeBytesAllocated; 1520 size_t targetSize = 1521 (nativeSize / gHs->targetUtilization) * HEAP_UTILIZATION_MAX; 1522 1523 if (targetSize > nativeSize + gHs->maxFree) { 1524 targetSize = nativeSize + gHs->maxFree; 1525 } else if (targetSize < nativeSize + gHs->minFree) { 1526 targetSize = nativeSize + gHs->minFree; 1527 } 1528 gHs->nativeFootprintGCWatermark = targetSize; 1529 gHs->nativeFootprintLimit = 2 * targetSize - nativeSize; 1530 } 1531 1532 void dvmHeapSourceRegisterNativeAllocation(int bytes) 1533 { 1534 /* If we have just done a GC, ensure that the finalizers are done and update 1535 * the native watermarks. 1536 */ 1537 if (gHs->nativeNeedToRunFinalization) { 1538 dvmRunFinalization(); 1539 dvmHeapSourceUpdateMaxNativeFootprint(); 1540 gHs->nativeNeedToRunFinalization = false; 1541 } 1542 1543 android_atomic_add(bytes, &gHs->nativeBytesAllocated); 1544 1545 if ((size_t)gHs->nativeBytesAllocated > gHs->nativeFootprintGCWatermark) { 1546 /* The second watermark is higher than the gc watermark. If you hit 1547 * this it means you are allocating native objects faster than the GC 1548 * can keep up with. If this occurs, we do a GC for alloc. 1549 */ 1550 if ((size_t)gHs->nativeBytesAllocated > gHs->nativeFootprintLimit) { 1551 Thread* self = dvmThreadSelf(); 1552 dvmRunFinalization(); 1553 if (dvmCheckException(self)) { 1554 return; 1555 } 1556 dvmLockHeap(); 1557 bool waited = dvmWaitForConcurrentGcToComplete(); 1558 dvmUnlockHeap(); 1559 if (waited) { 1560 // Just finished a GC, attempt to run finalizers. 1561 dvmRunFinalization(); 1562 if (dvmCheckException(self)) { 1563 return; 1564 } 1565 } 1566 1567 // If we still are over the watermark, attempt a GC for alloc and run finalizers. 1568 if ((size_t)gHs->nativeBytesAllocated > gHs->nativeFootprintLimit) { 1569 dvmLockHeap(); 1570 dvmWaitForConcurrentGcToComplete(); 1571 dvmCollectGarbageInternal(GC_FOR_MALLOC); 1572 dvmUnlockHeap(); 1573 dvmRunFinalization(); 1574 gHs->nativeNeedToRunFinalization = false; 1575 if (dvmCheckException(self)) { 1576 return; 1577 } 1578 } 1579 /* We have just run finalizers, update the native watermark since 1580 * it is very likely that finalizers released native managed 1581 * allocations. 1582 */ 1583 dvmHeapSourceUpdateMaxNativeFootprint(); 1584 } else { 1585 dvmSignalCond(&gHs->gcThreadCond); 1586 } 1587 } 1588 } 1589 1590 /* 1591 * Called from VMRuntime.registerNativeFree. 1592 */ 1593 void dvmHeapSourceRegisterNativeFree(int bytes) 1594 { 1595 int expected_size, new_size; 1596 do { 1597 expected_size = gHs->nativeBytesAllocated; 1598 new_size = expected_size - bytes; 1599 if (new_size < 0) { 1600 break; 1601 } 1602 } while (android_atomic_cas(expected_size, new_size, 1603 &gHs->nativeBytesAllocated)); 1604 } 1605