blob: 50303b7cb73eb0ded5585f5df78312176521139e [file] [log] [blame]
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001/*
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>
Carl Shapiroae188c62011-04-08 13:11:58 -070018#include <stdint.h>
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080019#include <sys/mman.h>
20#include <errno.h>
21
Carl Shapiroae188c62011-04-08 13:11:58 -070022#define SIZE_MAX UINT_MAX // TODO: get SIZE_MAX from stdint.h
23
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080024#include "Dalvik.h"
25#include "alloc/Heap.h"
26#include "alloc/HeapInternal.h"
27#include "alloc/HeapSource.h"
28#include "alloc/HeapBitmap.h"
Carl Shapiroc38b7ed2011-02-08 17:43:43 -080029#include "alloc/HeapBitmapInlines.h"
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080030
31// TODO: find a real header file for these.
Carl Shapiroae188c62011-04-08 13:11:58 -070032extern "C" int dlmalloc_trim(size_t);
33extern "C" void dlmalloc_walk_free_pages(void(*)(void*, void*, void*), void*);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080034
35static void snapIdealFootprint(void);
36static void setIdealFootprint(size_t max);
Carl Shapirodf9f08b2011-01-18 17:59:30 -080037static size_t getMaximumSize(const HeapSource *hs);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080038
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080039#define HEAP_UTILIZATION_MAX 1024
40#define DEFAULT_HEAP_UTILIZATION 512 // Range 1..HEAP_UTILIZATION_MAX
41#define HEAP_IDEAL_FREE (2 * 1024 * 1024)
42#define HEAP_MIN_FREE (HEAP_IDEAL_FREE / 4)
43
Carl Shapiro2c81bdc2010-09-07 16:19:01 -070044/* Start a concurrent collection when free memory falls under this
45 * many bytes.
Carl Shapiroec805ea2010-06-28 16:28:26 -070046 */
Carl Shapiro2c81bdc2010-09-07 16:19:01 -070047#define CONCURRENT_START (128 << 10)
48
49/* The next GC will not be concurrent when free memory after a GC is
50 * under this many bytes.
51 */
52#define CONCURRENT_MIN_FREE (CONCURRENT_START + (128 << 10))
Carl Shapiroec805ea2010-06-28 16:28:26 -070053
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080054#define HS_BOILERPLATE() \
55 do { \
56 assert(gDvm.gcHeap != NULL); \
57 assert(gDvm.gcHeap->heapSource != NULL); \
58 assert(gHs == gDvm.gcHeap->heapSource); \
59 } while (0)
60
61#define DEBUG_HEAP_SOURCE 0
62#if DEBUG_HEAP_SOURCE
63#define HSTRACE(...) LOG(LOG_INFO, LOG_TAG "-hs", __VA_ARGS__)
64#else
65#define HSTRACE(...) /**/
66#endif
67
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080068typedef struct {
69 /* The mspace to allocate from.
70 */
Barry Hayes06f254e2009-12-16 16:51:04 -080071 mspace msp;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080072
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080073 /* The largest size that this heap is allowed to grow to.
74 */
Carl Shapiro23966772011-01-16 14:05:53 -080075 size_t maximumSize;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080076
77 /* Number of bytes allocated from this mspace for objects,
78 * including any overhead. This value is NOT exact, and
79 * should only be used as an input for certain heuristics.
80 */
81 size_t bytesAllocated;
82
Carl Shapiro2c81bdc2010-09-07 16:19:01 -070083 /* Number of bytes allocated from this mspace at which a
84 * concurrent garbage collection will be started.
Carl Shapiroec805ea2010-06-28 16:28:26 -070085 */
Carl Shapiro2c81bdc2010-09-07 16:19:01 -070086 size_t concurrentStartBytes;
Carl Shapiroec805ea2010-06-28 16:28:26 -070087
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080088 /* Number of objects currently allocated from this mspace.
89 */
90 size_t objectsAllocated;
Carl Shapirof373efd2010-02-19 00:46:33 -080091
92 /*
93 * The lowest address of this heap, inclusive.
94 */
95 char *base;
96
97 /*
98 * The highest address of this heap, exclusive.
99 */
100 char *limit;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800101} Heap;
102
103struct HeapSource {
104 /* Target ideal heap utilization ratio; range 1..HEAP_UTILIZATION_MAX
105 */
106 size_t targetUtilization;
107
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800108 /* 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 */
Carl Shapiro23966772011-01-16 14:05:53 -0800114 size_t maximumSize;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800115
Carl Shapirodf9f08b2011-01-18 17:59:30 -0800116 /*
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
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800126 /* 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 /* The heaps; heaps[0] is always the active heap,
137 * which new objects should be allocated from.
138 */
139 Heap heaps[HEAP_SOURCE_MAX_HEAP_COUNT];
140
141 /* The current number of heaps.
142 */
143 size_t numHeaps;
144
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800145 /* True if zygote mode was active when the HeapSource was created.
146 */
147 bool sawZygote;
Carl Shapiroa199eb72010-02-09 16:26:30 -0800148
149 /*
150 * The base address of the virtual memory reservation.
151 */
152 char *heapBase;
153
154 /*
155 * The length in bytes of the virtual memory reservation.
156 */
157 size_t heapLength;
Carl Shapirof373efd2010-02-19 00:46:33 -0800158
159 /*
Carl Shapirod77f7fd2010-04-05 19:23:31 -0700160 * The live object bitmap.
Carl Shapirof373efd2010-02-19 00:46:33 -0800161 */
Carl Shapirod77f7fd2010-04-05 19:23:31 -0700162 HeapBitmap liveBits;
Carl Shapirof373efd2010-02-19 00:46:33 -0800163
164 /*
165 * The mark bitmap.
166 */
167 HeapBitmap markBits;
Carl Shapiroec805ea2010-06-28 16:28:26 -0700168
169 /*
170 * State for the GC daemon.
171 */
172 bool hasGcThread;
173 pthread_t gcThread;
174 bool gcThreadShutdown;
175 pthread_mutex_t gcThreadMutex;
176 pthread_cond_t gcThreadCond;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800177};
178
179#define hs2heap(hs_) (&((hs_)->heaps[0]))
180
181/*
182 * Returns true iff a soft limit is in effect for the active heap.
183 */
Carl Shapiro88a4f792011-01-14 19:05:23 -0800184static bool isSoftLimited(const HeapSource *hs)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800185{
Carl Shapiro2c81bdc2010-09-07 16:19:01 -0700186 /* softLimit will be either SIZE_MAX or the limit for the
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800187 * active mspace. idealSize can be greater than softLimit
188 * if there is more than one heap. If there is only one
Carl Shapiro2c81bdc2010-09-07 16:19:01 -0700189 * heap, a non-SIZE_MAX softLimit should always be the same
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800190 * as idealSize.
191 */
192 return hs->softLimit <= hs->idealSize;
193}
194
195/*
Carl Shapiro2c81bdc2010-09-07 16:19:01 -0700196 * Returns approximately the maximum number of bytes allowed to be
197 * allocated from the active heap before a GC is forced.
198 */
199static size_t
200getAllocLimit(const HeapSource *hs)
201{
Carl Shapiro88a4f792011-01-14 19:05:23 -0800202 if (isSoftLimited(hs)) {
Carl Shapiro2c81bdc2010-09-07 16:19:01 -0700203 return hs->softLimit;
204 } else {
205 return mspace_max_allowed_footprint(hs2heap(hs)->msp);
206 }
207}
208
209/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800210 * Returns the current footprint of all heaps. If includeActive
211 * is false, don't count the heap at index 0.
212 */
Carl Shapiro0f403d52011-01-16 17:20:49 -0800213static size_t oldHeapOverhead(const HeapSource *hs, bool includeActive)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800214{
215 size_t footprint = 0;
216 size_t i;
217
218 if (includeActive) {
219 i = 0;
220 } else {
221 i = 1;
222 }
223 for (/* i = i */; i < hs->numHeaps; i++) {
224//TODO: include size of bitmaps? If so, don't use bitsLen, listen to .max
225 footprint += mspace_footprint(hs->heaps[i].msp);
226 }
227 return footprint;
228}
229
230/*
231 * Returns the heap that <ptr> could have come from, or NULL
232 * if it could not have come from any heap.
233 */
Carl Shapiro0f403d52011-01-16 17:20:49 -0800234static Heap *ptr2heap(const HeapSource *hs, const void *ptr)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800235{
236 const size_t numHeaps = hs->numHeaps;
237 size_t i;
238
239//TODO: unroll this to HEAP_SOURCE_MAX_HEAP_COUNT
240 if (ptr != NULL) {
241 for (i = 0; i < numHeaps; i++) {
242 const Heap *const heap = &hs->heaps[i];
Carl Shapirof373efd2010-02-19 00:46:33 -0800243
244 if ((const char *)ptr >= heap->base && (const char *)ptr < heap->limit) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800245 return (Heap *)heap;
246 }
247 }
248 }
249 return NULL;
250}
251
252/*
253 * Functions to update heapSource->bytesAllocated when an object
254 * is allocated or freed. mspace_usable_size() will give
255 * us a much more accurate picture of heap utilization than
256 * the requested byte sizes would.
257 *
258 * These aren't exact, and should not be treated as such.
259 */
Carl Shapiroc36fb462011-03-08 17:09:25 -0800260static void countAllocation(Heap *heap, const void *ptr)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800261{
Carl Shapirof373efd2010-02-19 00:46:33 -0800262 HeapSource *hs;
263
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800264 assert(heap->bytesAllocated < mspace_footprint(heap->msp));
265
266 heap->bytesAllocated += mspace_usable_size(heap->msp, ptr) +
267 HEAP_SOURCE_CHUNK_OVERHEAD;
Carl Shapiroc36fb462011-03-08 17:09:25 -0800268 heap->objectsAllocated++;
269 hs = gDvm.gcHeap->heapSource;
270 dvmHeapBitmapSetObjectBit(&hs->liveBits, ptr);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800271
272 assert(heap->bytesAllocated < mspace_footprint(heap->msp));
273}
274
Carl Shapiro8881a802010-08-10 15:55:45 -0700275static void countFree(Heap *heap, const void *ptr, size_t *numBytes)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800276{
Carl Shapirof373efd2010-02-19 00:46:33 -0800277 HeapSource *hs;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800278 size_t delta;
279
280 delta = mspace_usable_size(heap->msp, ptr) + HEAP_SOURCE_CHUNK_OVERHEAD;
281 assert(delta > 0);
282 if (delta < heap->bytesAllocated) {
283 heap->bytesAllocated -= delta;
284 } else {
285 heap->bytesAllocated = 0;
286 }
Carl Shapiro8881a802010-08-10 15:55:45 -0700287 hs = gDvm.gcHeap->heapSource;
288 dvmHeapBitmapClearObjectBit(&hs->liveBits, ptr);
289 if (heap->objectsAllocated > 0) {
290 heap->objectsAllocated--;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800291 }
Carl Shapiro8881a802010-08-10 15:55:45 -0700292 *numBytes += delta;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800293}
294
295static HeapSource *gHs = NULL;
296
Barry Hayes06f254e2009-12-16 16:51:04 -0800297static mspace
Carl Shapiro23966772011-01-16 14:05:53 -0800298createMspace(void *base, size_t startSize, size_t maximumSize)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800299{
Barry Hayes06f254e2009-12-16 16:51:04 -0800300 mspace msp;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800301
302 /* Create an unlocked dlmalloc mspace to use as
Carl Shapiroff1c0e82011-01-11 16:33:53 -0800303 * a heap source.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800304 *
305 * We start off reserving heapSizeStart/2 bytes but
306 * letting the heap grow to heapSizeStart. This saves
307 * memory in the case where a process uses even less
308 * than the starting size.
309 */
Carl Shapiro7ed3c872011-01-13 15:56:42 -0800310 LOGV_HEAP("Creating VM heap of size %zu\n", startSize);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800311 errno = 0;
Carl Shapiroa199eb72010-02-09 16:26:30 -0800312 msp = create_contiguous_mspace_with_base(startSize/2,
Carl Shapiro23966772011-01-16 14:05:53 -0800313 maximumSize, /*locked=*/false, base);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800314 if (msp != NULL) {
315 /* Don't let the heap grow past the starting size without
316 * our intervention.
317 */
318 mspace_set_max_allowed_footprint(msp, startSize);
319 } else {
320 /* There's no guarantee that errno has meaning when the call
321 * fails, but it often does.
322 */
Carl Shapiro7ed3c872011-01-13 15:56:42 -0800323 LOGE_HEAP("Can't create VM heap of size (%zu,%zu): %s\n",
Carl Shapiro23966772011-01-16 14:05:53 -0800324 startSize/2, maximumSize, strerror(errno));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800325 }
326
327 return msp;
328}
329
Carl Shapiro6b4b3362011-02-09 16:36:12 -0800330/*
331 * Add the initial heap. Returns false if the initial heap was
332 * already added to the heap source.
333 */
334static bool addInitialHeap(HeapSource *hs, mspace msp, size_t maximumSize)
335{
336 assert(hs != NULL);
337 assert(msp != NULL);
338 if (hs->numHeaps != 0) {
339 return false;
340 }
341 hs->heaps[0].msp = msp;
342 hs->heaps[0].maximumSize = maximumSize;
343 hs->heaps[0].concurrentStartBytes = SIZE_MAX;
344 hs->heaps[0].base = hs->heapBase;
345 hs->heaps[0].limit = hs->heapBase + hs->heaps[0].maximumSize;
346 hs->numHeaps = 1;
347 return true;
348}
349
350/*
351 * Adds an additional heap to the heap source. Returns false if there
352 * are too many heaps or insufficient free space to add another heap.
353 */
354static bool addNewHeap(HeapSource *hs)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800355{
356 Heap heap;
357
Carl Shapiro6b4b3362011-02-09 16:36:12 -0800358 assert(hs != NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800359 if (hs->numHeaps >= HEAP_SOURCE_MAX_HEAP_COUNT) {
360 LOGE("Attempt to create too many heaps (%zd >= %zd)\n",
361 hs->numHeaps, HEAP_SOURCE_MAX_HEAP_COUNT);
362 dvmAbort();
363 return false;
364 }
365
366 memset(&heap, 0, sizeof(heap));
367
Carl Shapiro6b4b3362011-02-09 16:36:12 -0800368 /*
369 * Heap storage comes from a common virtual memory reservation.
370 * The new heap will start on the page after the old heap.
371 */
372 void *sbrk0 = contiguous_mspace_sbrk0(hs->heaps[0].msp);
373 char *base = (char *)ALIGN_UP_TO_PAGE_SIZE(sbrk0);
374 size_t overhead = base - hs->heaps[0].base;
375 assert(((size_t)hs->heaps[0].base & (SYSTEM_PAGE_SIZE - 1)) == 0);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800376
Carl Shapiro6b4b3362011-02-09 16:36:12 -0800377 if (overhead + HEAP_MIN_FREE >= hs->maximumSize) {
378 LOGE_HEAP("No room to create any more heaps "
379 "(%zd overhead, %zd max)",
380 overhead, hs->maximumSize);
381 return false;
382 }
383
384 heap.maximumSize = hs->growthLimit - overhead;
385 heap.concurrentStartBytes = HEAP_MIN_FREE - CONCURRENT_START;
386 heap.base = base;
387 heap.limit = heap.base + heap.maximumSize;
388 heap.msp = createMspace(base, HEAP_MIN_FREE, hs->maximumSize - overhead);
389 if (heap.msp == NULL) {
390 return false;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800391 }
392
393 /* Don't let the soon-to-be-old heap grow any further.
394 */
Carl Shapiro6b4b3362011-02-09 16:36:12 -0800395 hs->heaps[0].maximumSize = overhead;
396 hs->heaps[0].limit = base;
397 mspace msp = hs->heaps[0].msp;
398 mspace_set_max_allowed_footprint(msp, mspace_footprint(msp));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800399
400 /* Put the new heap in the list, at heaps[0].
401 * Shift existing heaps down.
402 */
403 memmove(&hs->heaps[1], &hs->heaps[0], hs->numHeaps * sizeof(hs->heaps[0]));
404 hs->heaps[0] = heap;
405 hs->numHeaps++;
406
407 return true;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800408}
409
410/*
Carl Shapiroec805ea2010-06-28 16:28:26 -0700411 * The garbage collection daemon. Initiates a concurrent collection
412 * when signaled.
413 */
414static void *gcDaemonThread(void* arg)
415{
416 dvmChangeStatus(NULL, THREAD_VMWAIT);
417 dvmLockMutex(&gHs->gcThreadMutex);
418 while (gHs->gcThreadShutdown != true) {
419 dvmWaitCond(&gHs->gcThreadCond, &gHs->gcThreadMutex);
420 dvmLockHeap();
421 dvmChangeStatus(NULL, THREAD_RUNNING);
Carl Shapirocc6f5112011-01-26 17:25:27 -0800422 dvmCollectGarbageInternal(GC_CONCURRENT);
Carl Shapiroec805ea2010-06-28 16:28:26 -0700423 dvmChangeStatus(NULL, THREAD_VMWAIT);
424 dvmUnlockHeap();
425 }
426 dvmChangeStatus(NULL, THREAD_RUNNING);
427 return NULL;
428}
429
430static bool gcDaemonStartup(void)
431{
432 dvmInitMutex(&gHs->gcThreadMutex);
433 pthread_cond_init(&gHs->gcThreadCond, NULL);
434 gHs->gcThreadShutdown = false;
435 gHs->hasGcThread = dvmCreateInternalThread(&gHs->gcThread, "GC",
436 gcDaemonThread, NULL);
437 return gHs->hasGcThread;
438}
439
440static void gcDaemonShutdown(void)
441{
Carl Shapirofe608772010-07-28 19:33:46 -0700442 if (gHs->hasGcThread) {
Carl Shapiroec805ea2010-06-28 16:28:26 -0700443 dvmLockMutex(&gHs->gcThreadMutex);
444 gHs->gcThreadShutdown = true;
445 dvmSignalCond(&gHs->gcThreadCond);
Carl Shapiroec805ea2010-06-28 16:28:26 -0700446 dvmUnlockMutex(&gHs->gcThreadMutex);
Carl Shapiro9e594772010-06-28 17:24:17 -0700447 pthread_join(gHs->gcThread, NULL);
Carl Shapiroec805ea2010-06-28 16:28:26 -0700448 }
449}
450
451/*
Carl Shapirofdf80522010-11-09 14:27:02 -0800452 * Create a stack big enough for the worst possible case, where the
453 * heap is perfectly full of the smallest object.
454 * TODO: be better about memory usage; use a smaller stack with
455 * overflow detection and recovery.
456 */
457static bool allocMarkStack(GcMarkStack *stack, size_t maximumSize)
458{
459 const char *name = "dalvik-mark-stack";
460 void *addr;
461
462 assert(stack != NULL);
463 stack->length = maximumSize * sizeof(Object*) /
464 (sizeof(Object) + HEAP_SOURCE_CHUNK_OVERHEAD);
465 addr = dvmAllocRegion(stack->length, PROT_READ | PROT_WRITE, name);
466 if (addr == NULL) {
467 return false;
468 }
469 stack->base = (const Object **)addr;
470 stack->limit = (const Object **)((char *)addr + stack->length);
471 stack->top = NULL;
472 madvise(stack->base, stack->length, MADV_DONTNEED);
473 return true;
474}
475
476static void freeMarkStack(GcMarkStack *stack)
477{
478 assert(stack != NULL);
479 munmap(stack->base, stack->length);
480 memset(stack, 0, sizeof(*stack));
481}
482
483/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800484 * Initializes the heap source; must be called before any other
485 * dvmHeapSource*() functions. Returns a GcHeap structure
486 * allocated from the heap source.
487 */
488GcHeap *
Carl Shapirodf9f08b2011-01-18 17:59:30 -0800489dvmHeapSourceStartup(size_t startSize, size_t maximumSize, size_t growthLimit)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800490{
491 GcHeap *gcHeap;
492 HeapSource *hs;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800493 mspace msp;
Carl Shapiroa199eb72010-02-09 16:26:30 -0800494 size_t length;
495 void *base;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800496
497 assert(gHs == NULL);
498
Carl Shapirodf9f08b2011-01-18 17:59:30 -0800499 if (!(startSize <= growthLimit && growthLimit <= maximumSize)) {
500 LOGE("Bad heap size parameters (start=%zd, max=%zd, limit=%zd)",
501 startSize, maximumSize, growthLimit);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800502 return NULL;
503 }
504
Carl Shapiroa199eb72010-02-09 16:26:30 -0800505 /*
506 * Allocate a contiguous region of virtual memory to subdivided
507 * among the heaps managed by the garbage collector.
508 */
Carl Shapiro23966772011-01-16 14:05:53 -0800509 length = ALIGN_UP_TO_PAGE_SIZE(maximumSize);
Barry Hayes6e5cf602010-06-22 12:32:59 -0700510 base = dvmAllocRegion(length, PROT_NONE, "dalvik-heap");
511 if (base == NULL) {
Carl Shapiroa199eb72010-02-09 16:26:30 -0800512 return NULL;
513 }
Carl Shapiroa199eb72010-02-09 16:26:30 -0800514
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800515 /* Create an unlocked dlmalloc mspace to use as
Carl Shapiroff1c0e82011-01-11 16:33:53 -0800516 * a heap source.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800517 */
Carl Shapiro23966772011-01-16 14:05:53 -0800518 msp = createMspace(base, startSize, maximumSize);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800519 if (msp == NULL) {
Carl Shapiroa199eb72010-02-09 16:26:30 -0800520 goto fail;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800521 }
522
Carl Shapiroc36fb462011-03-08 17:09:25 -0800523 gcHeap = (GcHeap *)malloc(sizeof(*gcHeap));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800524 if (gcHeap == NULL) {
525 LOGE_HEAP("Can't allocate heap descriptor\n");
526 goto fail;
527 }
528 memset(gcHeap, 0, sizeof(*gcHeap));
529
Carl Shapiroc36fb462011-03-08 17:09:25 -0800530 hs = (HeapSource *)malloc(sizeof(*hs));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800531 if (hs == NULL) {
532 LOGE_HEAP("Can't allocate heap source\n");
Carl Shapiroc36fb462011-03-08 17:09:25 -0800533 free(gcHeap);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800534 goto fail;
535 }
536 memset(hs, 0, sizeof(*hs));
537
538 hs->targetUtilization = DEFAULT_HEAP_UTILIZATION;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800539 hs->startSize = startSize;
Carl Shapiro23966772011-01-16 14:05:53 -0800540 hs->maximumSize = maximumSize;
Carl Shapirodf9f08b2011-01-18 17:59:30 -0800541 hs->growthLimit = growthLimit;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800542 hs->idealSize = startSize;
Carl Shapiro2c81bdc2010-09-07 16:19:01 -0700543 hs->softLimit = SIZE_MAX; // no soft limit at first
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800544 hs->numHeaps = 0;
545 hs->sawZygote = gDvm.zygote;
Carl Shapiroec805ea2010-06-28 16:28:26 -0700546 hs->hasGcThread = false;
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800547 hs->heapBase = (char *)base;
Carl Shapiroa199eb72010-02-09 16:26:30 -0800548 hs->heapLength = length;
Carl Shapiro6b4b3362011-02-09 16:36:12 -0800549 if (!addInitialHeap(hs, msp, growthLimit)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800550 LOGE_HEAP("Can't add initial heap\n");
551 goto fail;
552 }
Carl Shapirod77f7fd2010-04-05 19:23:31 -0700553 if (!dvmHeapBitmapInit(&hs->liveBits, base, length, "dalvik-bitmap-1")) {
554 LOGE_HEAP("Can't create liveBits\n");
Carl Shapirof373efd2010-02-19 00:46:33 -0800555 goto fail;
556 }
557 if (!dvmHeapBitmapInit(&hs->markBits, base, length, "dalvik-bitmap-2")) {
558 LOGE_HEAP("Can't create markBits\n");
Carl Shapirod77f7fd2010-04-05 19:23:31 -0700559 dvmHeapBitmapDelete(&hs->liveBits);
Carl Shapirof373efd2010-02-19 00:46:33 -0800560 goto fail;
561 }
Carl Shapiro23966772011-01-16 14:05:53 -0800562 if (!allocMarkStack(&gcHeap->markContext.stack, hs->maximumSize)) {
Carl Shapirofdf80522010-11-09 14:27:02 -0800563 LOGE("Can't create markStack");
564 dvmHeapBitmapDelete(&hs->markBits);
565 dvmHeapBitmapDelete(&hs->liveBits);
566 goto fail;
567 }
Carl Shapirof373efd2010-02-19 00:46:33 -0800568 gcHeap->markContext.bitmap = &hs->markBits;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800569 gcHeap->heapSource = hs;
570
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800571 gHs = hs;
572 return gcHeap;
573
574fail:
Carl Shapiroa199eb72010-02-09 16:26:30 -0800575 munmap(base, length);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800576 return NULL;
577}
578
Carl Shapiroec805ea2010-06-28 16:28:26 -0700579bool dvmHeapSourceStartupAfterZygote(void)
580{
581 return gDvm.concurrentMarkSweep ? gcDaemonStartup() : true;
582}
583
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800584/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800585 * This is called while in zygote mode, right before we fork() for the
586 * first time. We create a heap for all future zygote process allocations,
587 * in an attempt to avoid touching pages in the zygote heap. (This would
588 * probably be unnecessary if we had a compacting GC -- the source of our
589 * troubles is small allocations filling in the gaps from larger ones.)
590 */
591bool
592dvmHeapSourceStartupBeforeFork()
593{
594 HeapSource *hs = gHs; // use a local to avoid the implicit "volatile"
595
596 HS_BOILERPLATE();
597
598 assert(gDvm.zygote);
599
600 if (!gDvm.newZygoteHeapAllocated) {
601 /* Create a new heap for post-fork zygote allocations. We only
602 * try once, even if it fails.
603 */
Andy McFaddendced7942009-11-17 13:13:34 -0800604 LOGV("Splitting out new zygote heap\n");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800605 gDvm.newZygoteHeapAllocated = true;
Carl Shapiro6c355e52011-03-02 15:43:39 -0800606 dvmClearCardTable();
Carl Shapiro6b4b3362011-02-09 16:36:12 -0800607 return addNewHeap(hs);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800608 }
609 return true;
610}
611
Carl Shapiroec805ea2010-06-28 16:28:26 -0700612void dvmHeapSourceThreadShutdown(void)
613{
Carl Shapirofe608772010-07-28 19:33:46 -0700614 if (gDvm.gcHeap != NULL && gDvm.concurrentMarkSweep) {
Carl Shapirod7de4502010-07-15 11:26:26 -0700615 gcDaemonShutdown();
616 }
Carl Shapiroec805ea2010-06-28 16:28:26 -0700617}
618
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800619/*
Carl Shapiroa199eb72010-02-09 16:26:30 -0800620 * Tears down the entire GcHeap structure and all of the substructures
621 * attached to it. This call has the side effect of setting the given
622 * gcHeap pointer and gHs to NULL.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800623 */
624void
Carl Shapiroa199eb72010-02-09 16:26:30 -0800625dvmHeapSourceShutdown(GcHeap **gcHeap)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800626{
Carl Shapiro5396fcb2011-03-14 12:09:34 -0700627 assert(gcHeap != NULL);
Carl Shapiroa199eb72010-02-09 16:26:30 -0800628 if (*gcHeap != NULL && (*gcHeap)->heapSource != NULL) {
Carl Shapirofdf80522010-11-09 14:27:02 -0800629 HeapSource *hs = (*gcHeap)->heapSource;
Carl Shapirod77f7fd2010-04-05 19:23:31 -0700630 dvmHeapBitmapDelete(&hs->liveBits);
Carl Shapirof373efd2010-02-19 00:46:33 -0800631 dvmHeapBitmapDelete(&hs->markBits);
Carl Shapirofdf80522010-11-09 14:27:02 -0800632 freeMarkStack(&(*gcHeap)->markContext.stack);
Carl Shapiroa199eb72010-02-09 16:26:30 -0800633 munmap(hs->heapBase, hs->heapLength);
Carl Shapiroc36fb462011-03-08 17:09:25 -0800634 free(hs);
Carl Shapiroa199eb72010-02-09 16:26:30 -0800635 gHs = NULL;
Carl Shapiroc36fb462011-03-08 17:09:25 -0800636 free(*gcHeap);
Carl Shapiroa199eb72010-02-09 16:26:30 -0800637 *gcHeap = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800638 }
639}
640
641/*
Barry Hayesb874ab92010-07-14 08:13:18 -0700642 * Gets the begining of the allocation for the HeapSource.
643 */
644void *dvmHeapSourceGetBase(void)
645{
646 return gHs->heapBase;
647}
648
649/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800650 * Returns the requested value. If the per-heap stats are requested, fill
651 * them as well.
652 *
653 * Caller must hold the heap lock.
654 */
655size_t
656dvmHeapSourceGetValue(enum HeapSourceValueSpec spec, size_t perHeapStats[],
657 size_t arrayLen)
658{
659 HeapSource *hs = gHs;
660 size_t value = 0;
661 size_t total = 0;
662 size_t i;
663
664 HS_BOILERPLATE();
665
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800666 assert(arrayLen >= hs->numHeaps || perHeapStats == NULL);
667 for (i = 0; i < hs->numHeaps; i++) {
668 Heap *const heap = &hs->heaps[i];
669
670 switch (spec) {
671 case HS_FOOTPRINT:
672 value = mspace_footprint(heap->msp);
673 break;
674 case HS_ALLOWED_FOOTPRINT:
675 value = mspace_max_allowed_footprint(heap->msp);
676 break;
677 case HS_BYTES_ALLOCATED:
678 value = heap->bytesAllocated;
679 break;
680 case HS_OBJECTS_ALLOCATED:
681 value = heap->objectsAllocated;
682 break;
683 default:
684 // quiet gcc
685 break;
686 }
687 if (perHeapStats) {
688 perHeapStats[i] = value;
689 }
690 total += value;
691 }
692 return total;
693}
694
Carl Shapiro6c355e52011-03-02 15:43:39 -0800695void dvmHeapSourceGetRegions(uintptr_t *base, uintptr_t *max, uintptr_t *limit,
696 size_t numHeaps)
Carl Shapiroef75d462010-12-12 17:09:04 -0800697{
698 HeapSource *hs = gHs;
699 size_t i;
700
701 HS_BOILERPLATE();
702
703 assert(numHeaps <= hs->numHeaps);
704 for (i = 0; i < numHeaps; ++i) {
705 base[i] = (uintptr_t)hs->heaps[i].base;
Carl Shapiro6c355e52011-03-02 15:43:39 -0800706 if (max != NULL) {
707 max[i] = MIN((uintptr_t)hs->heaps[i].limit - 1, hs->markBits.max);
708 }
709 if (limit != NULL) {
710 limit[i] = (uintptr_t)hs->heaps[i].limit;
711 }
Carl Shapiroef75d462010-12-12 17:09:04 -0800712 }
713}
714
Barry Hayes962adba2010-03-17 12:12:39 -0700715/*
716 * Get the bitmap representing all live objects.
717 */
Carl Shapiroec805ea2010-06-28 16:28:26 -0700718HeapBitmap *dvmHeapSourceGetLiveBits(void)
Barry Hayes962adba2010-03-17 12:12:39 -0700719{
720 HS_BOILERPLATE();
721
Carl Shapirod77f7fd2010-04-05 19:23:31 -0700722 return &gHs->liveBits;
Barry Hayes962adba2010-03-17 12:12:39 -0700723}
724
Carl Shapiro21260712010-12-09 15:24:11 -0800725/*
726 * Get the bitmap representing all marked objects.
727 */
728HeapBitmap *dvmHeapSourceGetMarkBits(void)
729{
730 HS_BOILERPLATE();
731
732 return &gHs->markBits;
733}
734
Carl Shapirof373efd2010-02-19 00:46:33 -0800735void dvmHeapSourceSwapBitmaps(void)
736{
737 HeapBitmap tmp;
Barry Hayes81010a42010-07-19 14:07:01 -0700738
Carl Shapirod77f7fd2010-04-05 19:23:31 -0700739 tmp = gHs->liveBits;
740 gHs->liveBits = gHs->markBits;
Carl Shapirof373efd2010-02-19 00:46:33 -0800741 gHs->markBits = tmp;
Barry Hayes81010a42010-07-19 14:07:01 -0700742}
743
744void dvmHeapSourceZeroMarkBitmap(void)
745{
746 HS_BOILERPLATE();
747
Carl Shapirof373efd2010-02-19 00:46:33 -0800748 dvmHeapBitmapZero(&gHs->markBits);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800749}
750
Barry Hayes425848f2010-05-04 13:32:12 -0700751void dvmMarkImmuneObjects(const char *immuneLimit)
Carl Shapirod25566d2010-03-11 20:39:47 -0800752{
753 char *dst, *src;
Carl Shapiroe3c01da2010-05-20 22:54:18 -0700754 size_t i, index, length;
Carl Shapirod25566d2010-03-11 20:39:47 -0800755
756 /*
757 * Copy the contents of the live bit vector for immune object
758 * range into the mark bit vector.
759 */
Barry Hayes425848f2010-05-04 13:32:12 -0700760 /* The only values generated by dvmHeapSourceGetImmuneLimit() */
761 assert(immuneLimit == gHs->heaps[0].base ||
762 immuneLimit == NULL);
Carl Shapirod77f7fd2010-04-05 19:23:31 -0700763 assert(gHs->liveBits.base == gHs->markBits.base);
764 assert(gHs->liveBits.bitsLen == gHs->markBits.bitsLen);
Barry Hayes425848f2010-05-04 13:32:12 -0700765 /* heap[0] is never immune */
766 assert(gHs->heaps[0].base >= immuneLimit);
767 assert(gHs->heaps[0].limit > immuneLimit);
768
Carl Shapirod25566d2010-03-11 20:39:47 -0800769 for (i = 1; i < gHs->numHeaps; ++i) {
Barry Hayes425848f2010-05-04 13:32:12 -0700770 if (gHs->heaps[i].base < immuneLimit) {
771 assert(gHs->heaps[i].limit <= immuneLimit);
Barry Hayes425848f2010-05-04 13:32:12 -0700772 /* Compute the number of words to copy in the bitmap. */
773 index = HB_OFFSET_TO_INDEX(
774 (uintptr_t)gHs->heaps[i].base - gHs->liveBits.base);
775 /* Compute the starting offset in the live and mark bits. */
776 src = (char *)(gHs->liveBits.bits + index);
777 dst = (char *)(gHs->markBits.bits + index);
778 /* Compute the number of bytes of the live bitmap to copy. */
779 length = HB_OFFSET_TO_BYTE_INDEX(
780 gHs->heaps[i].limit - gHs->heaps[i].base);
781 /* Do the copy. */
782 memcpy(dst, src, length);
783 /* Make sure max points to the address of the highest set bit. */
784 if (gHs->markBits.max < (uintptr_t)gHs->heaps[i].limit) {
785 gHs->markBits.max = (uintptr_t)gHs->heaps[i].limit;
786 }
Carl Shapirod25566d2010-03-11 20:39:47 -0800787 }
788 }
789}
790
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800791/*
792 * Allocates <n> bytes of zeroed data.
793 */
794void *
795dvmHeapSourceAlloc(size_t n)
796{
797 HeapSource *hs = gHs;
798 Heap *heap;
799 void *ptr;
800
801 HS_BOILERPLATE();
802 heap = hs2heap(hs);
Carl Shapiroec47e2e2010-07-01 17:44:46 -0700803 if (heap->bytesAllocated + n > hs->softLimit) {
804 /*
805 * This allocation would push us over the soft limit; act as
806 * if the heap is full.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800807 */
808 LOGV_HEAP("softLimit of %zd.%03zdMB hit for %zd-byte allocation\n",
Carl Shapiroec47e2e2010-07-01 17:44:46 -0700809 FRACTIONAL_MB(hs->softLimit), n);
810 return NULL;
811 }
812 ptr = mspace_calloc(heap->msp, 1, n);
813 if (ptr == NULL) {
814 return NULL;
815 }
Carl Shapiroc36fb462011-03-08 17:09:25 -0800816 countAllocation(heap, ptr);
Carl Shapiroec47e2e2010-07-01 17:44:46 -0700817 /*
818 * Check to see if a concurrent GC should be initiated.
819 */
820 if (gDvm.gcHeap->gcRunning || !hs->hasGcThread) {
821 /*
822 * The garbage collector thread is already running or has yet
823 * to be started. Do nothing.
824 */
825 return ptr;
826 }
Carl Shapiro2c81bdc2010-09-07 16:19:01 -0700827 if (heap->bytesAllocated > heap->concurrentStartBytes) {
Carl Shapiroec47e2e2010-07-01 17:44:46 -0700828 /*
Carl Shapiro2c81bdc2010-09-07 16:19:01 -0700829 * We have exceeded the allocation threshold. Wake up the
Carl Shapiroec47e2e2010-07-01 17:44:46 -0700830 * garbage collector.
831 */
832 dvmSignalCond(&gHs->gcThreadCond);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800833 }
834 return ptr;
835}
836
837/* Remove any hard limits, try to allocate, and shrink back down.
838 * Last resort when trying to allocate an object.
839 */
840static void *
841heapAllocAndGrow(HeapSource *hs, Heap *heap, size_t n)
842{
843 void *ptr;
844 size_t max;
845
846 /* Grow as much as possible, but don't let the real footprint
Carl Shapiroe7bdd8b2010-12-17 15:34:52 -0800847 * go over the absolute max.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800848 */
Carl Shapiro23966772011-01-16 14:05:53 -0800849 max = heap->maximumSize;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800850
Carl Shapiroe7bdd8b2010-12-17 15:34:52 -0800851 mspace_set_max_allowed_footprint(heap->msp, max);
852 ptr = dvmHeapSourceAlloc(n);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800853
Carl Shapiroe7bdd8b2010-12-17 15:34:52 -0800854 /* Shrink back down as small as possible. Our caller may
855 * readjust max_allowed to a more appropriate value.
856 */
857 mspace_set_max_allowed_footprint(heap->msp,
858 mspace_footprint(heap->msp));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800859 return ptr;
860}
861
862/*
863 * Allocates <n> bytes of zeroed data, growing as much as possible
864 * if necessary.
865 */
866void *
867dvmHeapSourceAllocAndGrow(size_t n)
868{
869 HeapSource *hs = gHs;
870 Heap *heap;
871 void *ptr;
872 size_t oldIdealSize;
873
874 HS_BOILERPLATE();
875 heap = hs2heap(hs);
876
877 ptr = dvmHeapSourceAlloc(n);
878 if (ptr != NULL) {
879 return ptr;
880 }
881
882 oldIdealSize = hs->idealSize;
Carl Shapiro88a4f792011-01-14 19:05:23 -0800883 if (isSoftLimited(hs)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800884 /* We're soft-limited. Try removing the soft limit to
885 * see if we can allocate without actually growing.
886 */
Carl Shapiro2c81bdc2010-09-07 16:19:01 -0700887 hs->softLimit = SIZE_MAX;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800888 ptr = dvmHeapSourceAlloc(n);
889 if (ptr != NULL) {
890 /* Removing the soft limit worked; fix things up to
891 * reflect the new effective ideal size.
892 */
893 snapIdealFootprint();
894 return ptr;
895 }
Carl Shapiro2c81bdc2010-09-07 16:19:01 -0700896 // softLimit intentionally left at SIZE_MAX.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800897 }
898
899 /* We're not soft-limited. Grow the heap to satisfy the request.
900 * If this call fails, no footprints will have changed.
901 */
902 ptr = heapAllocAndGrow(hs, heap, n);
903 if (ptr != NULL) {
904 /* The allocation succeeded. Fix up the ideal size to
905 * reflect any footprint modifications that had to happen.
906 */
907 snapIdealFootprint();
908 } else {
909 /* We just couldn't do it. Restore the original ideal size,
910 * fixing up softLimit if necessary.
911 */
912 setIdealFootprint(oldIdealSize);
913 }
914 return ptr;
915}
916
917/*
Carl Shapiro8881a802010-08-10 15:55:45 -0700918 * Frees the first numPtrs objects in the ptrs list and returns the
919 * amount of reclaimed storage. The list must contain addresses all in
920 * the same mspace, and must be in increasing order. This implies that
921 * there are no duplicates, and no entries are NULL.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800922 */
Carl Shapiro8881a802010-08-10 15:55:45 -0700923size_t dvmHeapSourceFreeList(size_t numPtrs, void **ptrs)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800924{
925 Heap *heap;
Carl Shapiro8881a802010-08-10 15:55:45 -0700926 size_t numBytes;
Barry Hayesdde8ab02009-05-20 12:10:36 -0700927
928 HS_BOILERPLATE();
929
930 if (numPtrs == 0) {
Carl Shapiro8881a802010-08-10 15:55:45 -0700931 return 0;
Barry Hayesdde8ab02009-05-20 12:10:36 -0700932 }
933
934 assert(ptrs != NULL);
935 assert(*ptrs != NULL);
936 heap = ptr2heap(gHs, *ptrs);
Carl Shapiro8881a802010-08-10 15:55:45 -0700937 numBytes = 0;
Barry Hayesdde8ab02009-05-20 12:10:36 -0700938 if (heap != NULL) {
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800939 mspace msp = heap->msp;
Barry Hayesdde8ab02009-05-20 12:10:36 -0700940 // Calling mspace_free on shared heaps disrupts sharing too
941 // much. For heap[0] -- the 'active heap' -- we call
942 // mspace_free, but on the other heaps we only do some
943 // accounting.
944 if (heap == gHs->heaps) {
945 // mspace_merge_objects takes two allocated objects, and
946 // if the second immediately follows the first, will merge
947 // them, returning a larger object occupying the same
948 // memory. This is a local operation, and doesn't require
949 // dlmalloc to manipulate any freelists. It's pretty
950 // inexpensive compared to free().
951
952 // ptrs is an array of objects all in memory order, and if
953 // client code has been allocating lots of short-lived
954 // objects, this is likely to contain runs of objects all
955 // now garbage, and thus highly amenable to this optimization.
956
957 // Unroll the 0th iteration around the loop below,
958 // countFree ptrs[0] and initializing merged.
959 assert(ptrs[0] != NULL);
960 assert(ptr2heap(gHs, ptrs[0]) == heap);
Carl Shapiro8881a802010-08-10 15:55:45 -0700961 countFree(heap, ptrs[0], &numBytes);
Barry Hayesdde8ab02009-05-20 12:10:36 -0700962 void *merged = ptrs[0];
963
964 size_t i;
965 for (i = 1; i < numPtrs; i++) {
966 assert(merged != NULL);
967 assert(ptrs[i] != NULL);
968 assert((intptr_t)merged < (intptr_t)ptrs[i]);
969 assert(ptr2heap(gHs, ptrs[i]) == heap);
Carl Shapiro8881a802010-08-10 15:55:45 -0700970 countFree(heap, ptrs[i], &numBytes);
Barry Hayesdde8ab02009-05-20 12:10:36 -0700971 // Try to merge. If it works, merged now includes the
972 // memory of ptrs[i]. If it doesn't, free merged, and
973 // see if ptrs[i] starts a new run of adjacent
974 // objects to merge.
975 if (mspace_merge_objects(msp, merged, ptrs[i]) == NULL) {
976 mspace_free(msp, merged);
977 merged = ptrs[i];
978 }
979 }
980 assert(merged != NULL);
981 mspace_free(msp, merged);
982 } else {
983 // This is not an 'active heap'. Only do the accounting.
984 size_t i;
985 for (i = 0; i < numPtrs; i++) {
986 assert(ptrs[i] != NULL);
987 assert(ptr2heap(gHs, ptrs[i]) == heap);
Carl Shapiro8881a802010-08-10 15:55:45 -0700988 countFree(heap, ptrs[i], &numBytes);
Barry Hayesdde8ab02009-05-20 12:10:36 -0700989 }
990 }
991 }
Carl Shapiro8881a802010-08-10 15:55:45 -0700992 return numBytes;
Barry Hayesdde8ab02009-05-20 12:10:36 -0700993}
994
995/*
Barry Hayes364f9d92010-06-11 16:12:47 -0700996 * Returns true iff <ptr> is in the heap source.
997 */
998bool
999dvmHeapSourceContainsAddress(const void *ptr)
1000{
1001 HS_BOILERPLATE();
1002
1003 return (dvmHeapBitmapCoversAddress(&gHs->liveBits, ptr));
1004}
1005
1006/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001007 * Returns true iff <ptr> was allocated from the heap source.
1008 */
1009bool
1010dvmHeapSourceContains(const void *ptr)
1011{
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001012 HS_BOILERPLATE();
1013
Barry Hayes364f9d92010-06-11 16:12:47 -07001014 if (dvmHeapSourceContainsAddress(ptr)) {
Carl Shapirod77f7fd2010-04-05 19:23:31 -07001015 return dvmHeapBitmapIsObjectBitSet(&gHs->liveBits, ptr) != 0;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001016 }
1017 return false;
1018}
1019
1020/*
1021 * Returns the value of the requested flag.
1022 */
1023bool
1024dvmHeapSourceGetPtrFlag(const void *ptr, enum HeapSourcePtrFlag flag)
1025{
1026 if (ptr == NULL) {
1027 return false;
1028 }
1029
1030 if (flag == HS_CONTAINS) {
1031 return dvmHeapSourceContains(ptr);
1032 } else if (flag == HS_ALLOCATED_IN_ZYGOTE) {
1033 HeapSource *hs = gHs;
1034
1035 HS_BOILERPLATE();
1036
1037 if (hs->sawZygote) {
1038 Heap *heap;
1039
1040 heap = ptr2heap(hs, ptr);
1041 if (heap != NULL) {
1042 /* If the object is not in the active heap, we assume that
1043 * it was allocated as part of zygote.
1044 */
1045 return heap != hs->heaps;
1046 }
1047 }
1048 /* The pointer is outside of any known heap, or we are not
1049 * running in zygote mode.
1050 */
1051 return false;
1052 }
1053
1054 return false;
1055}
1056
1057/*
1058 * Returns the number of usable bytes in an allocated chunk; the size
1059 * may be larger than the size passed to dvmHeapSourceAlloc().
1060 */
1061size_t
1062dvmHeapSourceChunkSize(const void *ptr)
1063{
1064 Heap *heap;
1065
1066 HS_BOILERPLATE();
1067
1068 heap = ptr2heap(gHs, ptr);
1069 if (heap != NULL) {
1070 return mspace_usable_size(heap->msp, ptr);
1071 }
1072 return 0;
1073}
1074
1075/*
1076 * Returns the number of bytes that the heap source has allocated
1077 * from the system using sbrk/mmap, etc.
1078 *
1079 * Caller must hold the heap lock.
1080 */
1081size_t
1082dvmHeapSourceFootprint()
1083{
1084 HS_BOILERPLATE();
1085
1086//TODO: include size of bitmaps?
1087 return oldHeapOverhead(gHs, true);
1088}
1089
Carl Shapirodf9f08b2011-01-18 17:59:30 -08001090static size_t getMaximumSize(const HeapSource *hs)
1091{
1092 return hs->growthLimit;
1093}
1094
1095/*
1096 * Returns the current maximum size of the heap source respecting any
1097 * growth limits.
1098 */
1099size_t dvmHeapSourceGetMaximumSize()
1100{
1101 HS_BOILERPLATE();
1102 return getMaximumSize(gHs);
1103}
1104
1105/*
1106 * Removes any growth limits. Allows the user to allocate up to the
1107 * maximum heap size.
1108 */
1109void dvmClearGrowthLimit()
1110{
1111 size_t overhead;
1112
1113 HS_BOILERPLATE();
1114 dvmLockHeap();
1115 dvmWaitForConcurrentGcToComplete();
1116 gHs->growthLimit = gHs->maximumSize;
1117 overhead = oldHeapOverhead(gHs, false);
1118 gHs->heaps[0].maximumSize = gHs->maximumSize - overhead;
1119 dvmUnlockHeap();
1120}
1121
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001122/*
Carl Shapiroe7bdd8b2010-12-17 15:34:52 -08001123 * Return the real bytes used by old heaps plus the soft usage of the
1124 * current heap. When a soft limit is in effect, this is effectively
1125 * what it's compared against (though, in practice, it only looks at
1126 * the current heap).
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001127 */
1128static size_t
1129getSoftFootprint(bool includeActive)
1130{
1131 HeapSource *hs = gHs;
1132 size_t ret;
1133
1134 HS_BOILERPLATE();
1135
Carl Shapiroe7bdd8b2010-12-17 15:34:52 -08001136 ret = oldHeapOverhead(hs, false);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001137 if (includeActive) {
1138 ret += hs->heaps[0].bytesAllocated;
1139 }
1140
1141 return ret;
1142}
1143
1144/*
1145 * Gets the maximum number of bytes that the heap source is allowed
1146 * to allocate from the system.
1147 */
1148size_t
1149dvmHeapSourceGetIdealFootprint()
1150{
1151 HeapSource *hs = gHs;
1152
1153 HS_BOILERPLATE();
1154
1155 return hs->idealSize;
1156}
1157
1158/*
1159 * Sets the soft limit, handling any necessary changes to the allowed
1160 * footprint of the active heap.
1161 */
1162static void
1163setSoftLimit(HeapSource *hs, size_t softLimit)
1164{
1165 /* Compare against the actual footprint, rather than the
1166 * max_allowed, because the heap may not have grown all the
1167 * way to the allowed size yet.
1168 */
Barry Hayes06f254e2009-12-16 16:51:04 -08001169 mspace msp = hs->heaps[0].msp;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001170 size_t currentHeapSize = mspace_footprint(msp);
1171 if (softLimit < currentHeapSize) {
1172 /* Don't let the heap grow any more, and impose a soft limit.
1173 */
1174 mspace_set_max_allowed_footprint(msp, currentHeapSize);
1175 hs->softLimit = softLimit;
1176 } else {
1177 /* Let the heap grow to the requested max, and remove any
1178 * soft limit, if set.
1179 */
1180 mspace_set_max_allowed_footprint(msp, softLimit);
Carl Shapiro2c81bdc2010-09-07 16:19:01 -07001181 hs->softLimit = SIZE_MAX;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001182 }
1183}
1184
1185/*
1186 * Sets the maximum number of bytes that the heap source is allowed
1187 * to allocate from the system. Clamps to the appropriate maximum
1188 * value.
1189 */
1190static void
1191setIdealFootprint(size_t max)
1192{
1193 HeapSource *hs = gHs;
1194#if DEBUG_HEAP_SOURCE
1195 HeapSource oldHs = *hs;
Barry Hayes06f254e2009-12-16 16:51:04 -08001196 mspace msp = hs->heaps[0].msp;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001197 size_t oldAllowedFootprint =
1198 mspace_max_allowed_footprint(msp);
1199#endif
Carl Shapirodf9f08b2011-01-18 17:59:30 -08001200 size_t maximumSize;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001201
1202 HS_BOILERPLATE();
1203
Carl Shapirodf9f08b2011-01-18 17:59:30 -08001204 maximumSize = getMaximumSize(hs);
1205 if (max > maximumSize) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001206 LOGI_HEAP("Clamp target GC heap from %zd.%03zdMB to %u.%03uMB\n",
1207 FRACTIONAL_MB(max),
Carl Shapirodf9f08b2011-01-18 17:59:30 -08001208 FRACTIONAL_MB(maximumSize));
1209 max = maximumSize;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001210 }
1211
1212 /* Convert max into a size that applies to the active heap.
Carl Shapiroe7bdd8b2010-12-17 15:34:52 -08001213 * Old heaps will count against the ideal size.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001214 */
1215 size_t overhead = getSoftFootprint(false);
1216 size_t activeMax;
1217 if (overhead < max) {
1218 activeMax = max - overhead;
1219 } else {
1220 activeMax = 0;
1221 }
1222
1223 setSoftLimit(hs, activeMax);
1224 hs->idealSize = max;
1225
1226 HSTRACE("IDEAL %zd->%zd (%d), soft %zd->%zd (%d), allowed %zd->%zd (%d), "
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001227 oldHs.idealSize, hs->idealSize, hs->idealSize - oldHs.idealSize,
1228 oldHs.softLimit, hs->softLimit, hs->softLimit - oldHs.softLimit,
1229 oldAllowedFootprint, mspace_max_allowed_footprint(msp),
Carl Shapiroe7bdd8b2010-12-17 15:34:52 -08001230 mspace_max_allowed_footprint(msp) - oldAllowedFootprint);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001231
1232}
1233
1234/*
1235 * Make the ideal footprint equal to the current footprint.
1236 */
1237static void
1238snapIdealFootprint()
1239{
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001240 HS_BOILERPLATE();
1241
1242 setIdealFootprint(getSoftFootprint(true));
1243}
1244
1245/*
1246 * Gets the current ideal heap utilization, represented as a number
1247 * between zero and one.
1248 */
1249float dvmGetTargetHeapUtilization()
1250{
1251 HeapSource *hs = gHs;
1252
1253 HS_BOILERPLATE();
1254
1255 return (float)hs->targetUtilization / (float)HEAP_UTILIZATION_MAX;
1256}
1257
1258/*
1259 * Sets the new ideal heap utilization, represented as a number
1260 * between zero and one.
1261 */
1262void dvmSetTargetHeapUtilization(float newTarget)
1263{
1264 HeapSource *hs = gHs;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001265
1266 HS_BOILERPLATE();
1267
1268 /* Clamp it to a reasonable range.
1269 */
1270 // TODO: This may need some tuning.
1271 if (newTarget < 0.2) {
1272 newTarget = 0.2;
1273 } else if (newTarget > 0.8) {
1274 newTarget = 0.8;
1275 }
1276
1277 hs->targetUtilization =
1278 (size_t)(newTarget * (float)HEAP_UTILIZATION_MAX);
Carl Shapirode750892010-06-08 16:37:12 -07001279 LOGV("Set heap target utilization to %zd/%d (%f)\n",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001280 hs->targetUtilization, HEAP_UTILIZATION_MAX, newTarget);
1281}
1282
1283/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001284 * Given the size of a live set, returns the ideal heap size given
1285 * the current target utilization and MIN/MAX values.
1286 *
1287 * targetUtilization is in the range 1..HEAP_UTILIZATION_MAX.
1288 */
1289static size_t
Carl Shapiro98389d02010-02-14 23:11:47 -08001290getUtilizationTarget(size_t liveSize, size_t targetUtilization)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001291{
1292 size_t targetSize;
1293
1294 /* Use the current target utilization ratio to determine the
1295 * ideal heap size based on the size of the live set.
1296 */
1297 targetSize = (liveSize / targetUtilization) * HEAP_UTILIZATION_MAX;
1298
1299 /* Cap the amount of free space, though, so we don't end up
1300 * with, e.g., 8MB of free space when the live set size hits 8MB.
1301 */
1302 if (targetSize > liveSize + HEAP_IDEAL_FREE) {
1303 targetSize = liveSize + HEAP_IDEAL_FREE;
1304 } else if (targetSize < liveSize + HEAP_MIN_FREE) {
1305 targetSize = liveSize + HEAP_MIN_FREE;
1306 }
1307 return targetSize;
1308}
1309
1310/*
1311 * Given the current contents of the active heap, increase the allowed
1312 * heap footprint to match the target utilization ratio. This
1313 * should only be called immediately after a full mark/sweep.
1314 */
1315void dvmHeapSourceGrowForUtilization()
1316{
1317 HeapSource *hs = gHs;
1318 Heap *heap;
1319 size_t targetHeapSize;
1320 size_t currentHeapUsed;
1321 size_t oldIdealSize;
1322 size_t newHeapMax;
1323 size_t overhead;
Carl Shapiro2c81bdc2010-09-07 16:19:01 -07001324 size_t freeBytes;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001325
1326 HS_BOILERPLATE();
1327 heap = hs2heap(hs);
1328
1329 /* Use the current target utilization ratio to determine the
1330 * ideal heap size based on the size of the live set.
1331 * Note that only the active heap plays any part in this.
1332 *
1333 * Avoid letting the old heaps influence the target free size,
1334 * because they may be full of objects that aren't actually
1335 * in the working set. Just look at the allocated size of
1336 * the current heap.
1337 */
1338 currentHeapUsed = heap->bytesAllocated;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001339 targetHeapSize =
Carl Shapiro98389d02010-02-14 23:11:47 -08001340 getUtilizationTarget(currentHeapUsed, hs->targetUtilization);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001341
1342 /* The ideal size includes the old heaps; add overhead so that
1343 * it can be immediately subtracted again in setIdealFootprint().
1344 * If the target heap size would exceed the max, setIdealFootprint()
1345 * will clamp it to a legal value.
1346 */
1347 overhead = getSoftFootprint(false);
1348 oldIdealSize = hs->idealSize;
1349 setIdealFootprint(targetHeapSize + overhead);
1350
Carl Shapiro2c81bdc2010-09-07 16:19:01 -07001351 freeBytes = getAllocLimit(hs);
1352 if (freeBytes < CONCURRENT_MIN_FREE) {
1353 /* Not enough free memory to allow a concurrent GC. */
1354 heap->concurrentStartBytes = SIZE_MAX;
1355 } else {
1356 heap->concurrentStartBytes = freeBytes - CONCURRENT_START;
1357 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001358 newHeapMax = mspace_max_allowed_footprint(heap->msp);
Carl Shapiro88a4f792011-01-14 19:05:23 -08001359 if (isSoftLimited(hs)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001360 LOGD_HEAP("GC old usage %zd.%zd%%; now "
1361 "%zd.%03zdMB used / %zd.%03zdMB soft max "
1362 "(%zd.%03zdMB over, "
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001363 "%zd.%03zdMB real max)\n",
1364 FRACTIONAL_PCT(currentHeapUsed, oldIdealSize),
1365 FRACTIONAL_MB(currentHeapUsed),
1366 FRACTIONAL_MB(hs->softLimit),
1367 FRACTIONAL_MB(overhead),
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001368 FRACTIONAL_MB(newHeapMax));
1369 } else {
1370 LOGD_HEAP("GC old usage %zd.%zd%%; now "
1371 "%zd.%03zdMB used / %zd.%03zdMB real max "
Carl Shapiroe7bdd8b2010-12-17 15:34:52 -08001372 "(%zd.%03zdMB over)\n",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001373 FRACTIONAL_PCT(currentHeapUsed, oldIdealSize),
1374 FRACTIONAL_MB(currentHeapUsed),
1375 FRACTIONAL_MB(newHeapMax),
Carl Shapiroe7bdd8b2010-12-17 15:34:52 -08001376 FRACTIONAL_MB(overhead));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001377 }
1378}
1379
1380/*
1381 * Return free pages to the system.
1382 * TODO: move this somewhere else, especially the native heap part.
1383 */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001384static void releasePagesInRange(void *start, void *end, void *nbytes)
1385{
1386 /* Linux requires that the madvise() start address is page-aligned.
1387 * We also align the end address.
1388 */
1389 start = (void *)ALIGN_UP_TO_PAGE_SIZE(start);
Andy McFadden96516932009-10-28 17:39:02 -07001390 end = (void *)((size_t)end & ~(SYSTEM_PAGE_SIZE - 1));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001391 if (start < end) {
1392 size_t length = (char *)end - (char *)start;
1393 madvise(start, length, MADV_DONTNEED);
1394 *(size_t *)nbytes += length;
1395 }
1396}
1397
1398/*
1399 * Return unused memory to the system if possible.
1400 */
1401void
1402dvmHeapSourceTrim(size_t bytesTrimmed[], size_t arrayLen)
1403{
1404 HeapSource *hs = gHs;
1405 size_t nativeBytes, heapBytes;
1406 size_t i;
1407
1408 HS_BOILERPLATE();
1409
1410 assert(arrayLen >= hs->numHeaps);
1411
1412 heapBytes = 0;
1413 for (i = 0; i < hs->numHeaps; i++) {
1414 Heap *heap = &hs->heaps[i];
1415
1416 /* Return the wilderness chunk to the system.
1417 */
1418 mspace_trim(heap->msp, 0);
1419
1420 /* Return any whole free pages to the system.
1421 */
1422 bytesTrimmed[i] = 0;
Carl Shapirode750892010-06-08 16:37:12 -07001423 mspace_walk_free_pages(heap->msp, releasePagesInRange,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001424 &bytesTrimmed[i]);
1425 heapBytes += bytesTrimmed[i];
1426 }
1427
1428 /* Same for the native heap.
1429 */
1430 dlmalloc_trim(0);
1431 nativeBytes = 0;
1432 dlmalloc_walk_free_pages(releasePagesInRange, &nativeBytes);
1433
1434 LOGD_HEAP("madvised %zd (GC) + %zd (native) = %zd total bytes\n",
1435 heapBytes, nativeBytes, heapBytes + nativeBytes);
1436}
1437
1438/*
1439 * Walks over the heap source and passes every allocated and
1440 * free chunk to the callback.
1441 */
1442void
1443dvmHeapSourceWalk(void(*callback)(const void *chunkptr, size_t chunklen,
1444 const void *userptr, size_t userlen,
1445 void *arg),
1446 void *arg)
1447{
1448 HeapSource *hs = gHs;
1449 size_t i;
1450
1451 HS_BOILERPLATE();
1452
1453 /* Walk the heaps from oldest to newest.
1454 */
1455//TODO: do this in address order
1456 for (i = hs->numHeaps; i > 0; --i) {
1457 mspace_walk_heap(hs->heaps[i-1].msp, callback, arg);
1458 }
1459}
1460
1461/*
1462 * Gets the number of heaps available in the heap source.
1463 *
1464 * Caller must hold the heap lock, because gHs caches a field
1465 * in gDvm.gcHeap.
1466 */
1467size_t
1468dvmHeapSourceGetNumHeaps()
1469{
1470 HeapSource *hs = gHs;
1471
1472 HS_BOILERPLATE();
1473
1474 return hs->numHeaps;
1475}
1476
Carl Shapirocc6f5112011-01-26 17:25:27 -08001477void *dvmHeapSourceGetImmuneLimit(bool isPartial)
Carl Shapirod25566d2010-03-11 20:39:47 -08001478{
Carl Shapirocc6f5112011-01-26 17:25:27 -08001479 if (isPartial) {
Carl Shapirod25566d2010-03-11 20:39:47 -08001480 return hs2heap(gHs)->base;
1481 } else {
1482 return NULL;
1483 }
1484}