blob: 26e5701f6840c6f4014ec42668a5edab84ddc4d1 [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 Shapiro2c81bdc2010-09-07 16:19:01 -070018#include <stdint.h> // for SIZE_MAX
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080019#include <sys/mman.h>
20#include <errno.h>
21
22#include "Dalvik.h"
23#include "alloc/Heap.h"
24#include "alloc/HeapInternal.h"
25#include "alloc/HeapSource.h"
26#include "alloc/HeapBitmap.h"
27
28// TODO: find a real header file for these.
29extern int dlmalloc_trim(size_t);
30extern void dlmalloc_walk_free_pages(void(*)(void*, void*, void*), void*);
31
32static void snapIdealFootprint(void);
33static void setIdealFootprint(size_t max);
34
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080035#define ALIGN_UP_TO_PAGE_SIZE(p) \
Andy McFadden96516932009-10-28 17:39:02 -070036 (((size_t)(p) + (SYSTEM_PAGE_SIZE - 1)) & ~(SYSTEM_PAGE_SIZE - 1))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080037#define ALIGN_DOWN_TO_PAGE_SIZE(p) \
Andy McFadden96516932009-10-28 17:39:02 -070038 ((size_t)(p) & ~(SYSTEM_PAGE_SIZE - 1))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080039
40#define HEAP_UTILIZATION_MAX 1024
41#define DEFAULT_HEAP_UTILIZATION 512 // Range 1..HEAP_UTILIZATION_MAX
42#define HEAP_IDEAL_FREE (2 * 1024 * 1024)
43#define HEAP_MIN_FREE (HEAP_IDEAL_FREE / 4)
44
Carl Shapiro2c81bdc2010-09-07 16:19:01 -070045/* Start a concurrent collection when free memory falls under this
46 * many bytes.
Carl Shapiroec805ea2010-06-28 16:28:26 -070047 */
Carl Shapiro2c81bdc2010-09-07 16:19:01 -070048#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))
Carl Shapiroec805ea2010-06-28 16:28:26 -070054
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080055#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#define DEBUG_HEAP_SOURCE 0
63#if DEBUG_HEAP_SOURCE
64#define HSTRACE(...) LOG(LOG_INFO, LOG_TAG "-hs", __VA_ARGS__)
65#else
66#define HSTRACE(...) /**/
67#endif
68
69/*
70=======================================================
71=======================================================
72=======================================================
73
74How will this be used?
75allocating/freeing: Heap.c just wants to say "alloc(n)" and get a ptr
76 - if allocating in large doesn't work, try allocating from small
77Heap.c will use HeapSource.h; HeapSource.c will do the right thing
78 between small and large
79 - some operations should be abstracted; put in a structure
80
81How do we manage the size trade-offs?
82- keep mspace max footprint clamped to actual footprint
83- if small-alloc returns null, adjust large vs. small ratio
84 - give small all available slack and retry
85 - success or fail, snap back to actual footprint and give rest to large
86
87managed as "small actual" + "large actual" + "delta to allowed total footprint"
88- when allocating from one source or the other, give the delta to the
89 active source, but snap back afterwards
90- that may not work so great for a gc heap, because small will always consume.
91 - but we need to use the memory, and the current max is the amount we
92 need to fill before a GC.
93
94Find a way to permanently steal pages from the middle of the heap
95 - segment tricks?
96
97Allocate String and char[] in a separate heap?
98
99Maybe avoid growing small heap, even if there's slack? Look at
100live ratio of small heap after a gc; scale it based on that.
101
102=======================================================
103=======================================================
104=======================================================
105*/
106
107typedef struct {
108 /* The mspace to allocate from.
109 */
Barry Hayes06f254e2009-12-16 16:51:04 -0800110 mspace msp;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800111
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800112 /* The largest size that this heap is allowed to grow to.
113 */
114 size_t absoluteMaxSize;
115
116 /* Number of bytes allocated from this mspace for objects,
117 * including any overhead. This value is NOT exact, and
118 * should only be used as an input for certain heuristics.
119 */
120 size_t bytesAllocated;
121
Carl Shapiro2c81bdc2010-09-07 16:19:01 -0700122 /* Number of bytes allocated from this mspace at which a
123 * concurrent garbage collection will be started.
Carl Shapiroec805ea2010-06-28 16:28:26 -0700124 */
Carl Shapiro2c81bdc2010-09-07 16:19:01 -0700125 size_t concurrentStartBytes;
Carl Shapiroec805ea2010-06-28 16:28:26 -0700126
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800127 /* Number of objects currently allocated from this mspace.
128 */
129 size_t objectsAllocated;
Carl Shapirof373efd2010-02-19 00:46:33 -0800130
131 /*
132 * The lowest address of this heap, inclusive.
133 */
134 char *base;
135
136 /*
137 * The highest address of this heap, exclusive.
138 */
139 char *limit;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800140} Heap;
141
142struct HeapSource {
143 /* Target ideal heap utilization ratio; range 1..HEAP_UTILIZATION_MAX
144 */
145 size_t targetUtilization;
146
147 /* Requested minimum heap size, or zero if there is no minimum.
148 */
149 size_t minimumSize;
150
151 /* The starting heap size.
152 */
153 size_t startSize;
154
155 /* The largest that the heap source as a whole is allowed to grow.
156 */
157 size_t absoluteMaxSize;
158
159 /* The desired max size of the heap source as a whole.
160 */
161 size_t idealSize;
162
163 /* The maximum number of bytes allowed to be allocated from the
164 * active heap before a GC is forced. This is used to "shrink" the
165 * heap in lieu of actual compaction.
166 */
167 size_t softLimit;
168
169 /* The heaps; heaps[0] is always the active heap,
170 * which new objects should be allocated from.
171 */
172 Heap heaps[HEAP_SOURCE_MAX_HEAP_COUNT];
173
174 /* The current number of heaps.
175 */
176 size_t numHeaps;
177
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800178 /* True if zygote mode was active when the HeapSource was created.
179 */
180 bool sawZygote;
Carl Shapiroa199eb72010-02-09 16:26:30 -0800181
182 /*
183 * The base address of the virtual memory reservation.
184 */
185 char *heapBase;
186
187 /*
188 * The length in bytes of the virtual memory reservation.
189 */
190 size_t heapLength;
Carl Shapirof373efd2010-02-19 00:46:33 -0800191
192 /*
Carl Shapirod77f7fd2010-04-05 19:23:31 -0700193 * The live object bitmap.
Carl Shapirof373efd2010-02-19 00:46:33 -0800194 */
Carl Shapirod77f7fd2010-04-05 19:23:31 -0700195 HeapBitmap liveBits;
Carl Shapirof373efd2010-02-19 00:46:33 -0800196
197 /*
198 * The mark bitmap.
199 */
200 HeapBitmap markBits;
Carl Shapiroec805ea2010-06-28 16:28:26 -0700201
202 /*
203 * State for the GC daemon.
204 */
205 bool hasGcThread;
206 pthread_t gcThread;
207 bool gcThreadShutdown;
208 pthread_mutex_t gcThreadMutex;
209 pthread_cond_t gcThreadCond;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800210};
211
212#define hs2heap(hs_) (&((hs_)->heaps[0]))
213
214/*
215 * Returns true iff a soft limit is in effect for the active heap.
216 */
217static inline bool
218softLimited(const HeapSource *hs)
219{
Carl Shapiro2c81bdc2010-09-07 16:19:01 -0700220 /* softLimit will be either SIZE_MAX or the limit for the
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800221 * active mspace. idealSize can be greater than softLimit
222 * if there is more than one heap. If there is only one
Carl Shapiro2c81bdc2010-09-07 16:19:01 -0700223 * heap, a non-SIZE_MAX softLimit should always be the same
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800224 * as idealSize.
225 */
226 return hs->softLimit <= hs->idealSize;
227}
228
229/*
Carl Shapiro2c81bdc2010-09-07 16:19:01 -0700230 * Returns approximately the maximum number of bytes allowed to be
231 * allocated from the active heap before a GC is forced.
232 */
233static size_t
234getAllocLimit(const HeapSource *hs)
235{
236 if (softLimited(hs)) {
237 return hs->softLimit;
238 } else {
239 return mspace_max_allowed_footprint(hs2heap(hs)->msp);
240 }
241}
242
243/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800244 * Returns the current footprint of all heaps. If includeActive
245 * is false, don't count the heap at index 0.
246 */
247static inline size_t
248oldHeapOverhead(const HeapSource *hs, bool includeActive)
249{
250 size_t footprint = 0;
251 size_t i;
252
253 if (includeActive) {
254 i = 0;
255 } else {
256 i = 1;
257 }
258 for (/* i = i */; i < hs->numHeaps; i++) {
259//TODO: include size of bitmaps? If so, don't use bitsLen, listen to .max
260 footprint += mspace_footprint(hs->heaps[i].msp);
261 }
262 return footprint;
263}
264
265/*
266 * Returns the heap that <ptr> could have come from, or NULL
267 * if it could not have come from any heap.
268 */
269static inline Heap *
270ptr2heap(const HeapSource *hs, const void *ptr)
271{
272 const size_t numHeaps = hs->numHeaps;
273 size_t i;
274
275//TODO: unroll this to HEAP_SOURCE_MAX_HEAP_COUNT
276 if (ptr != NULL) {
277 for (i = 0; i < numHeaps; i++) {
278 const Heap *const heap = &hs->heaps[i];
Carl Shapirof373efd2010-02-19 00:46:33 -0800279
280 if ((const char *)ptr >= heap->base && (const char *)ptr < heap->limit) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800281 return (Heap *)heap;
282 }
283 }
284 }
285 return NULL;
286}
287
288/*
289 * Functions to update heapSource->bytesAllocated when an object
290 * is allocated or freed. mspace_usable_size() will give
291 * us a much more accurate picture of heap utilization than
292 * the requested byte sizes would.
293 *
294 * These aren't exact, and should not be treated as such.
295 */
Carl Shapiroec47e2e2010-07-01 17:44:46 -0700296static void countAllocation(Heap *heap, const void *ptr, bool isObj)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800297{
Carl Shapirof373efd2010-02-19 00:46:33 -0800298 HeapSource *hs;
299
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800300 assert(heap->bytesAllocated < mspace_footprint(heap->msp));
301
302 heap->bytesAllocated += mspace_usable_size(heap->msp, ptr) +
303 HEAP_SOURCE_CHUNK_OVERHEAD;
304 if (isObj) {
305 heap->objectsAllocated++;
Carl Shapirof373efd2010-02-19 00:46:33 -0800306 hs = gDvm.gcHeap->heapSource;
Carl Shapirod77f7fd2010-04-05 19:23:31 -0700307 dvmHeapBitmapSetObjectBit(&hs->liveBits, ptr);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800308 }
309
310 assert(heap->bytesAllocated < mspace_footprint(heap->msp));
311}
312
Carl Shapiro8881a802010-08-10 15:55:45 -0700313static void countFree(Heap *heap, const void *ptr, size_t *numBytes)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800314{
Carl Shapirof373efd2010-02-19 00:46:33 -0800315 HeapSource *hs;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800316 size_t delta;
317
318 delta = mspace_usable_size(heap->msp, ptr) + HEAP_SOURCE_CHUNK_OVERHEAD;
319 assert(delta > 0);
320 if (delta < heap->bytesAllocated) {
321 heap->bytesAllocated -= delta;
322 } else {
323 heap->bytesAllocated = 0;
324 }
Carl Shapiro8881a802010-08-10 15:55:45 -0700325 hs = gDvm.gcHeap->heapSource;
326 dvmHeapBitmapClearObjectBit(&hs->liveBits, ptr);
327 if (heap->objectsAllocated > 0) {
328 heap->objectsAllocated--;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800329 }
Carl Shapiro8881a802010-08-10 15:55:45 -0700330 *numBytes += delta;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800331}
332
333static HeapSource *gHs = NULL;
334
Barry Hayes06f254e2009-12-16 16:51:04 -0800335static mspace
Carl Shapiroa199eb72010-02-09 16:26:30 -0800336createMspace(void *base, size_t startSize, size_t absoluteMaxSize)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800337{
Barry Hayes06f254e2009-12-16 16:51:04 -0800338 mspace msp;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800339
340 /* Create an unlocked dlmalloc mspace to use as
341 * a small-object heap source.
342 *
343 * We start off reserving heapSizeStart/2 bytes but
344 * letting the heap grow to heapSizeStart. This saves
345 * memory in the case where a process uses even less
346 * than the starting size.
347 */
348 LOGV_HEAP("Creating VM heap of size %u\n", startSize);
349 errno = 0;
Carl Shapiroa199eb72010-02-09 16:26:30 -0800350 msp = create_contiguous_mspace_with_base(startSize/2,
351 absoluteMaxSize, /*locked=*/false, base);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800352 if (msp != NULL) {
353 /* Don't let the heap grow past the starting size without
354 * our intervention.
355 */
356 mspace_set_max_allowed_footprint(msp, startSize);
357 } else {
358 /* There's no guarantee that errno has meaning when the call
359 * fails, but it often does.
360 */
Elliott Hughesc5f53e22010-06-11 16:13:15 -0700361 LOGE_HEAP("Can't create VM heap of size (%u,%u): %s\n",
362 startSize/2, absoluteMaxSize, strerror(errno));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800363 }
364
365 return msp;
366}
367
368static bool
Barry Hayes06f254e2009-12-16 16:51:04 -0800369addNewHeap(HeapSource *hs, mspace msp, size_t mspAbsoluteMaxSize)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800370{
371 Heap heap;
372
373 if (hs->numHeaps >= HEAP_SOURCE_MAX_HEAP_COUNT) {
374 LOGE("Attempt to create too many heaps (%zd >= %zd)\n",
375 hs->numHeaps, HEAP_SOURCE_MAX_HEAP_COUNT);
376 dvmAbort();
377 return false;
378 }
379
380 memset(&heap, 0, sizeof(heap));
381
382 if (msp != NULL) {
383 heap.msp = msp;
384 heap.absoluteMaxSize = mspAbsoluteMaxSize;
Carl Shapiro2c81bdc2010-09-07 16:19:01 -0700385 heap.concurrentStartBytes = SIZE_MAX;
Carl Shapirof373efd2010-02-19 00:46:33 -0800386 heap.base = hs->heapBase;
387 heap.limit = hs->heapBase + heap.absoluteMaxSize;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800388 } else {
Carl Shapiro88c57e12010-10-10 18:50:22 -0700389 void *sbrk0 = contiguous_mspace_sbrk0(hs->heaps[0].msp);
390 char *base = (char *)ALIGN_UP_TO_PAGE_SIZE(sbrk0);
391 size_t overhead = base - hs->heaps[0].base;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800392
Carl Shapiro88c57e12010-10-10 18:50:22 -0700393 assert(((size_t)hs->heaps[0].base & (SYSTEM_PAGE_SIZE - 1)) == 0);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800394 if (overhead + HEAP_MIN_FREE >= hs->absoluteMaxSize) {
395 LOGE_HEAP("No room to create any more heaps "
396 "(%zd overhead, %zd max)\n",
397 overhead, hs->absoluteMaxSize);
398 return false;
399 }
Carl Shapirod25566d2010-03-11 20:39:47 -0800400 hs->heaps[0].absoluteMaxSize = overhead;
Carl Shapirof373efd2010-02-19 00:46:33 -0800401 hs->heaps[0].limit = base;
Carl Shapiro88c57e12010-10-10 18:50:22 -0700402 heap.absoluteMaxSize = hs->absoluteMaxSize - overhead;
Carl Shapiroa199eb72010-02-09 16:26:30 -0800403 heap.msp = createMspace(base, HEAP_MIN_FREE, heap.absoluteMaxSize);
Carl Shapiro2c81bdc2010-09-07 16:19:01 -0700404 heap.concurrentStartBytes = HEAP_MIN_FREE - CONCURRENT_START;
Carl Shapirof373efd2010-02-19 00:46:33 -0800405 heap.base = base;
406 heap.limit = heap.base + heap.absoluteMaxSize;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800407 if (heap.msp == NULL) {
408 return false;
409 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800410 }
411
412 /* Don't let the soon-to-be-old heap grow any further.
413 */
414 if (hs->numHeaps > 0) {
Barry Hayes06f254e2009-12-16 16:51:04 -0800415 mspace msp = hs->heaps[0].msp;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800416 mspace_set_max_allowed_footprint(msp, mspace_footprint(msp));
417 }
418
419 /* Put the new heap in the list, at heaps[0].
420 * Shift existing heaps down.
421 */
422 memmove(&hs->heaps[1], &hs->heaps[0], hs->numHeaps * sizeof(hs->heaps[0]));
423 hs->heaps[0] = heap;
424 hs->numHeaps++;
425
426 return true;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800427}
428
429/*
Carl Shapiroec805ea2010-06-28 16:28:26 -0700430 * The garbage collection daemon. Initiates a concurrent collection
431 * when signaled.
432 */
433static void *gcDaemonThread(void* arg)
434{
435 dvmChangeStatus(NULL, THREAD_VMWAIT);
436 dvmLockMutex(&gHs->gcThreadMutex);
437 while (gHs->gcThreadShutdown != true) {
438 dvmWaitCond(&gHs->gcThreadCond, &gHs->gcThreadMutex);
439 dvmLockHeap();
440 dvmChangeStatus(NULL, THREAD_RUNNING);
441 dvmCollectGarbageInternal(false, GC_CONCURRENT);
442 dvmChangeStatus(NULL, THREAD_VMWAIT);
443 dvmUnlockHeap();
444 }
445 dvmChangeStatus(NULL, THREAD_RUNNING);
446 return NULL;
447}
448
449static bool gcDaemonStartup(void)
450{
451 dvmInitMutex(&gHs->gcThreadMutex);
452 pthread_cond_init(&gHs->gcThreadCond, NULL);
453 gHs->gcThreadShutdown = false;
454 gHs->hasGcThread = dvmCreateInternalThread(&gHs->gcThread, "GC",
455 gcDaemonThread, NULL);
456 return gHs->hasGcThread;
457}
458
459static void gcDaemonShutdown(void)
460{
Carl Shapirofe608772010-07-28 19:33:46 -0700461 if (gHs->hasGcThread) {
Carl Shapiroec805ea2010-06-28 16:28:26 -0700462 dvmLockMutex(&gHs->gcThreadMutex);
463 gHs->gcThreadShutdown = true;
464 dvmSignalCond(&gHs->gcThreadCond);
Carl Shapiroec805ea2010-06-28 16:28:26 -0700465 dvmUnlockMutex(&gHs->gcThreadMutex);
Carl Shapiro9e594772010-06-28 17:24:17 -0700466 pthread_join(gHs->gcThread, NULL);
Carl Shapiroec805ea2010-06-28 16:28:26 -0700467 }
468}
469
470/*
Carl Shapirofdf80522010-11-09 14:27:02 -0800471 * Create a stack big enough for the worst possible case, where the
472 * heap is perfectly full of the smallest object.
473 * TODO: be better about memory usage; use a smaller stack with
474 * overflow detection and recovery.
475 */
476static bool allocMarkStack(GcMarkStack *stack, size_t maximumSize)
477{
478 const char *name = "dalvik-mark-stack";
479 void *addr;
480
481 assert(stack != NULL);
482 stack->length = maximumSize * sizeof(Object*) /
483 (sizeof(Object) + HEAP_SOURCE_CHUNK_OVERHEAD);
484 addr = dvmAllocRegion(stack->length, PROT_READ | PROT_WRITE, name);
485 if (addr == NULL) {
486 return false;
487 }
488 stack->base = (const Object **)addr;
489 stack->limit = (const Object **)((char *)addr + stack->length);
490 stack->top = NULL;
491 madvise(stack->base, stack->length, MADV_DONTNEED);
492 return true;
493}
494
495static void freeMarkStack(GcMarkStack *stack)
496{
497 assert(stack != NULL);
498 munmap(stack->base, stack->length);
499 memset(stack, 0, sizeof(*stack));
500}
501
502/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800503 * Initializes the heap source; must be called before any other
504 * dvmHeapSource*() functions. Returns a GcHeap structure
505 * allocated from the heap source.
506 */
507GcHeap *
508dvmHeapSourceStartup(size_t startSize, size_t absoluteMaxSize)
509{
510 GcHeap *gcHeap;
511 HeapSource *hs;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800512 mspace msp;
Carl Shapiroa199eb72010-02-09 16:26:30 -0800513 size_t length;
514 void *base;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800515
516 assert(gHs == NULL);
517
518 if (startSize > absoluteMaxSize) {
519 LOGE("Bad heap parameters (start=%d, max=%d)\n",
520 startSize, absoluteMaxSize);
521 return NULL;
522 }
523
Carl Shapiroa199eb72010-02-09 16:26:30 -0800524 /*
525 * Allocate a contiguous region of virtual memory to subdivided
526 * among the heaps managed by the garbage collector.
527 */
528 length = ALIGN_UP_TO_PAGE_SIZE(absoluteMaxSize);
Barry Hayes6e5cf602010-06-22 12:32:59 -0700529 base = dvmAllocRegion(length, PROT_NONE, "dalvik-heap");
530 if (base == NULL) {
Carl Shapiroa199eb72010-02-09 16:26:30 -0800531 return NULL;
532 }
Carl Shapiroa199eb72010-02-09 16:26:30 -0800533
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800534 /* Create an unlocked dlmalloc mspace to use as
535 * the small object heap source.
536 */
Carl Shapiroa199eb72010-02-09 16:26:30 -0800537 msp = createMspace(base, startSize, absoluteMaxSize);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800538 if (msp == NULL) {
Carl Shapiroa199eb72010-02-09 16:26:30 -0800539 goto fail;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800540 }
541
542 /* Allocate a descriptor from the heap we just created.
543 */
544 gcHeap = mspace_malloc(msp, sizeof(*gcHeap));
545 if (gcHeap == NULL) {
546 LOGE_HEAP("Can't allocate heap descriptor\n");
547 goto fail;
548 }
549 memset(gcHeap, 0, sizeof(*gcHeap));
550
551 hs = mspace_malloc(msp, sizeof(*hs));
552 if (hs == NULL) {
553 LOGE_HEAP("Can't allocate heap source\n");
554 goto fail;
555 }
556 memset(hs, 0, sizeof(*hs));
557
558 hs->targetUtilization = DEFAULT_HEAP_UTILIZATION;
559 hs->minimumSize = 0;
560 hs->startSize = startSize;
561 hs->absoluteMaxSize = absoluteMaxSize;
562 hs->idealSize = startSize;
Carl Shapiro2c81bdc2010-09-07 16:19:01 -0700563 hs->softLimit = SIZE_MAX; // no soft limit at first
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800564 hs->numHeaps = 0;
565 hs->sawZygote = gDvm.zygote;
Carl Shapiroec805ea2010-06-28 16:28:26 -0700566 hs->hasGcThread = false;
Carl Shapiroa199eb72010-02-09 16:26:30 -0800567 hs->heapBase = base;
568 hs->heapLength = length;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800569 if (!addNewHeap(hs, msp, absoluteMaxSize)) {
570 LOGE_HEAP("Can't add initial heap\n");
571 goto fail;
572 }
Carl Shapirod77f7fd2010-04-05 19:23:31 -0700573 if (!dvmHeapBitmapInit(&hs->liveBits, base, length, "dalvik-bitmap-1")) {
574 LOGE_HEAP("Can't create liveBits\n");
Carl Shapirof373efd2010-02-19 00:46:33 -0800575 goto fail;
576 }
577 if (!dvmHeapBitmapInit(&hs->markBits, base, length, "dalvik-bitmap-2")) {
578 LOGE_HEAP("Can't create markBits\n");
Carl Shapirod77f7fd2010-04-05 19:23:31 -0700579 dvmHeapBitmapDelete(&hs->liveBits);
Carl Shapirof373efd2010-02-19 00:46:33 -0800580 goto fail;
581 }
Carl Shapirofdf80522010-11-09 14:27:02 -0800582 if (!allocMarkStack(&gcHeap->markContext.stack, hs->absoluteMaxSize)) {
583 LOGE("Can't create markStack");
584 dvmHeapBitmapDelete(&hs->markBits);
585 dvmHeapBitmapDelete(&hs->liveBits);
586 goto fail;
587 }
Carl Shapirof373efd2010-02-19 00:46:33 -0800588 gcHeap->markContext.bitmap = &hs->markBits;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800589 gcHeap->heapSource = hs;
590
591 countAllocation(hs2heap(hs), gcHeap, false);
592 countAllocation(hs2heap(hs), hs, false);
593
594 gHs = hs;
595 return gcHeap;
596
597fail:
Carl Shapiroa199eb72010-02-09 16:26:30 -0800598 munmap(base, length);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800599 return NULL;
600}
601
Carl Shapiroec805ea2010-06-28 16:28:26 -0700602bool dvmHeapSourceStartupAfterZygote(void)
603{
604 return gDvm.concurrentMarkSweep ? gcDaemonStartup() : true;
605}
606
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800607/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800608 * This is called while in zygote mode, right before we fork() for the
609 * first time. We create a heap for all future zygote process allocations,
610 * in an attempt to avoid touching pages in the zygote heap. (This would
611 * probably be unnecessary if we had a compacting GC -- the source of our
612 * troubles is small allocations filling in the gaps from larger ones.)
613 */
614bool
615dvmHeapSourceStartupBeforeFork()
616{
617 HeapSource *hs = gHs; // use a local to avoid the implicit "volatile"
618
619 HS_BOILERPLATE();
620
621 assert(gDvm.zygote);
622
623 if (!gDvm.newZygoteHeapAllocated) {
624 /* Create a new heap for post-fork zygote allocations. We only
625 * try once, even if it fails.
626 */
Andy McFaddendced7942009-11-17 13:13:34 -0800627 LOGV("Splitting out new zygote heap\n");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800628 gDvm.newZygoteHeapAllocated = true;
629 return addNewHeap(hs, NULL, 0);
630 }
631 return true;
632}
633
Carl Shapiroec805ea2010-06-28 16:28:26 -0700634void dvmHeapSourceThreadShutdown(void)
635{
Carl Shapirofe608772010-07-28 19:33:46 -0700636 if (gDvm.gcHeap != NULL && gDvm.concurrentMarkSweep) {
Carl Shapirod7de4502010-07-15 11:26:26 -0700637 gcDaemonShutdown();
638 }
Carl Shapiroec805ea2010-06-28 16:28:26 -0700639}
640
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800641/*
Carl Shapiroa199eb72010-02-09 16:26:30 -0800642 * Tears down the entire GcHeap structure and all of the substructures
643 * attached to it. This call has the side effect of setting the given
644 * gcHeap pointer and gHs to NULL.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800645 */
646void
Carl Shapiroa199eb72010-02-09 16:26:30 -0800647dvmHeapSourceShutdown(GcHeap **gcHeap)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800648{
Carl Shapiroa199eb72010-02-09 16:26:30 -0800649 if (*gcHeap != NULL && (*gcHeap)->heapSource != NULL) {
Carl Shapirofdf80522010-11-09 14:27:02 -0800650 HeapSource *hs = (*gcHeap)->heapSource;
Carl Shapiroa199eb72010-02-09 16:26:30 -0800651 assert((char *)*gcHeap >= hs->heapBase);
652 assert((char *)*gcHeap < hs->heapBase + hs->heapLength);
Carl Shapirod77f7fd2010-04-05 19:23:31 -0700653 dvmHeapBitmapDelete(&hs->liveBits);
Carl Shapirof373efd2010-02-19 00:46:33 -0800654 dvmHeapBitmapDelete(&hs->markBits);
Carl Shapirofdf80522010-11-09 14:27:02 -0800655 freeMarkStack(&(*gcHeap)->markContext.stack);
Carl Shapiroa199eb72010-02-09 16:26:30 -0800656 munmap(hs->heapBase, hs->heapLength);
657 gHs = NULL;
658 *gcHeap = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800659 }
660}
661
662/*
Barry Hayesb874ab92010-07-14 08:13:18 -0700663 * Gets the begining of the allocation for the HeapSource.
664 */
665void *dvmHeapSourceGetBase(void)
666{
667 return gHs->heapBase;
668}
669
670/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800671 * Returns the requested value. If the per-heap stats are requested, fill
672 * them as well.
673 *
674 * Caller must hold the heap lock.
675 */
676size_t
677dvmHeapSourceGetValue(enum HeapSourceValueSpec spec, size_t perHeapStats[],
678 size_t arrayLen)
679{
680 HeapSource *hs = gHs;
681 size_t value = 0;
682 size_t total = 0;
683 size_t i;
684
685 HS_BOILERPLATE();
686
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800687 assert(arrayLen >= hs->numHeaps || perHeapStats == NULL);
688 for (i = 0; i < hs->numHeaps; i++) {
689 Heap *const heap = &hs->heaps[i];
690
691 switch (spec) {
692 case HS_FOOTPRINT:
693 value = mspace_footprint(heap->msp);
694 break;
695 case HS_ALLOWED_FOOTPRINT:
696 value = mspace_max_allowed_footprint(heap->msp);
697 break;
698 case HS_BYTES_ALLOCATED:
699 value = heap->bytesAllocated;
700 break;
701 case HS_OBJECTS_ALLOCATED:
702 value = heap->objectsAllocated;
703 break;
704 default:
705 // quiet gcc
706 break;
707 }
708 if (perHeapStats) {
709 perHeapStats[i] = value;
710 }
711 total += value;
712 }
713 return total;
714}
715
Carl Shapirof373efd2010-02-19 00:46:33 -0800716static void aliasBitmap(HeapBitmap *dst, HeapBitmap *src,
717 uintptr_t base, uintptr_t max) {
718 size_t offset;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800719
Carl Shapirof373efd2010-02-19 00:46:33 -0800720 dst->base = base;
721 dst->max = max;
Barry Hayes73f3e6f2010-07-15 08:58:10 -0700722 dst->bitsLen = HB_OFFSET_TO_BYTE_INDEX(max - base) + sizeof(dst->bits);
723 /* The exclusive limit from bitsLen is greater than the inclusive max. */
724 assert(base + HB_MAX_OFFSET(dst) > max);
Barry Hayes8a0b5232010-07-21 11:22:04 -0700725 /* The exclusive limit is at most one word of bits beyond max. */
726 assert((base + HB_MAX_OFFSET(dst)) - max <=
Barry Hayes73f3e6f2010-07-15 08:58:10 -0700727 HB_OBJECT_ALIGNMENT * HB_BITS_PER_WORD);
Carl Shapirod25566d2010-03-11 20:39:47 -0800728 dst->allocLen = dst->bitsLen;
Carl Shapirof373efd2010-02-19 00:46:33 -0800729 offset = base - src->base;
730 assert(HB_OFFSET_TO_MASK(offset) == 1 << 31);
731 dst->bits = &src->bits[HB_OFFSET_TO_INDEX(offset)];
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800732}
733
734/*
Carl Shapirof373efd2010-02-19 00:46:33 -0800735 * Initializes a vector of object and mark bits to the object and mark
Barry Hayese168ebd2010-05-07 09:19:46 -0700736 * bits of each heap. The bits are aliased to the heapsource
Carl Shapirof373efd2010-02-19 00:46:33 -0800737 * object and mark bitmaps. This routine is used by the sweep code
738 * which needs to free each object in the correct heap.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800739 */
Carl Shapirod77f7fd2010-04-05 19:23:31 -0700740void dvmHeapSourceGetObjectBitmaps(HeapBitmap liveBits[], HeapBitmap markBits[],
Carl Shapirof373efd2010-02-19 00:46:33 -0800741 size_t numHeaps)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800742{
743 HeapSource *hs = gHs;
Carl Shapirof373efd2010-02-19 00:46:33 -0800744 uintptr_t base, max;
Carl Shapiroe3c01da2010-05-20 22:54:18 -0700745 size_t i;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800746
747 HS_BOILERPLATE();
748
Carl Shapirof373efd2010-02-19 00:46:33 -0800749 assert(numHeaps == hs->numHeaps);
750 for (i = 0; i < hs->numHeaps; ++i) {
751 base = (uintptr_t)hs->heaps[i].base;
Barry Hayes73f3e6f2010-07-15 08:58:10 -0700752 /* -1 because limit is exclusive but max is inclusive. */
Carl Shapiroe6a1b4d2010-08-17 18:33:56 -0700753 max = MIN((uintptr_t)hs->heaps[i].limit - 1, hs->markBits.max);
Carl Shapirod77f7fd2010-04-05 19:23:31 -0700754 aliasBitmap(&liveBits[i], &hs->liveBits, base, max);
Carl Shapirof373efd2010-02-19 00:46:33 -0800755 aliasBitmap(&markBits[i], &hs->markBits, base, max);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800756 }
Carl Shapirof373efd2010-02-19 00:46:33 -0800757}
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800758
Barry Hayes962adba2010-03-17 12:12:39 -0700759/*
760 * Get the bitmap representing all live objects.
761 */
Carl Shapiroec805ea2010-06-28 16:28:26 -0700762HeapBitmap *dvmHeapSourceGetLiveBits(void)
Barry Hayes962adba2010-03-17 12:12:39 -0700763{
764 HS_BOILERPLATE();
765
Carl Shapirod77f7fd2010-04-05 19:23:31 -0700766 return &gHs->liveBits;
Barry Hayes962adba2010-03-17 12:12:39 -0700767}
768
Carl Shapirof373efd2010-02-19 00:46:33 -0800769void dvmHeapSourceSwapBitmaps(void)
770{
771 HeapBitmap tmp;
Barry Hayes81010a42010-07-19 14:07:01 -0700772
Carl Shapirod77f7fd2010-04-05 19:23:31 -0700773 tmp = gHs->liveBits;
774 gHs->liveBits = gHs->markBits;
Carl Shapirof373efd2010-02-19 00:46:33 -0800775 gHs->markBits = tmp;
Barry Hayes81010a42010-07-19 14:07:01 -0700776}
777
778void dvmHeapSourceZeroMarkBitmap(void)
779{
780 HS_BOILERPLATE();
781
Carl Shapirof373efd2010-02-19 00:46:33 -0800782 dvmHeapBitmapZero(&gHs->markBits);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800783}
784
Barry Hayes425848f2010-05-04 13:32:12 -0700785void dvmMarkImmuneObjects(const char *immuneLimit)
Carl Shapirod25566d2010-03-11 20:39:47 -0800786{
787 char *dst, *src;
Carl Shapiroe3c01da2010-05-20 22:54:18 -0700788 size_t i, index, length;
Carl Shapirod25566d2010-03-11 20:39:47 -0800789
790 /*
791 * Copy the contents of the live bit vector for immune object
792 * range into the mark bit vector.
793 */
Barry Hayes425848f2010-05-04 13:32:12 -0700794 /* The only values generated by dvmHeapSourceGetImmuneLimit() */
795 assert(immuneLimit == gHs->heaps[0].base ||
796 immuneLimit == NULL);
Carl Shapirod77f7fd2010-04-05 19:23:31 -0700797 assert(gHs->liveBits.base == gHs->markBits.base);
798 assert(gHs->liveBits.bitsLen == gHs->markBits.bitsLen);
Barry Hayes425848f2010-05-04 13:32:12 -0700799 /* heap[0] is never immune */
800 assert(gHs->heaps[0].base >= immuneLimit);
801 assert(gHs->heaps[0].limit > immuneLimit);
802
Carl Shapirod25566d2010-03-11 20:39:47 -0800803 for (i = 1; i < gHs->numHeaps; ++i) {
Barry Hayes425848f2010-05-04 13:32:12 -0700804 if (gHs->heaps[i].base < immuneLimit) {
805 assert(gHs->heaps[i].limit <= immuneLimit);
Barry Hayes425848f2010-05-04 13:32:12 -0700806 /* Compute the number of words to copy in the bitmap. */
807 index = HB_OFFSET_TO_INDEX(
808 (uintptr_t)gHs->heaps[i].base - gHs->liveBits.base);
809 /* Compute the starting offset in the live and mark bits. */
810 src = (char *)(gHs->liveBits.bits + index);
811 dst = (char *)(gHs->markBits.bits + index);
812 /* Compute the number of bytes of the live bitmap to copy. */
813 length = HB_OFFSET_TO_BYTE_INDEX(
814 gHs->heaps[i].limit - gHs->heaps[i].base);
815 /* Do the copy. */
816 memcpy(dst, src, length);
817 /* Make sure max points to the address of the highest set bit. */
818 if (gHs->markBits.max < (uintptr_t)gHs->heaps[i].limit) {
819 gHs->markBits.max = (uintptr_t)gHs->heaps[i].limit;
820 }
Carl Shapirod25566d2010-03-11 20:39:47 -0800821 }
822 }
823}
824
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800825/*
826 * Allocates <n> bytes of zeroed data.
827 */
828void *
829dvmHeapSourceAlloc(size_t n)
830{
831 HeapSource *hs = gHs;
832 Heap *heap;
833 void *ptr;
834
835 HS_BOILERPLATE();
836 heap = hs2heap(hs);
Carl Shapiroec47e2e2010-07-01 17:44:46 -0700837 if (heap->bytesAllocated + n > hs->softLimit) {
838 /*
839 * This allocation would push us over the soft limit; act as
840 * if the heap is full.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800841 */
842 LOGV_HEAP("softLimit of %zd.%03zdMB hit for %zd-byte allocation\n",
Carl Shapiroec47e2e2010-07-01 17:44:46 -0700843 FRACTIONAL_MB(hs->softLimit), n);
844 return NULL;
845 }
846 ptr = mspace_calloc(heap->msp, 1, n);
847 if (ptr == NULL) {
848 return NULL;
849 }
850 countAllocation(heap, ptr, true);
851 /*
852 * Check to see if a concurrent GC should be initiated.
853 */
854 if (gDvm.gcHeap->gcRunning || !hs->hasGcThread) {
855 /*
856 * The garbage collector thread is already running or has yet
857 * to be started. Do nothing.
858 */
859 return ptr;
860 }
Carl Shapiro2c81bdc2010-09-07 16:19:01 -0700861 if (heap->bytesAllocated > heap->concurrentStartBytes) {
Carl Shapiroec47e2e2010-07-01 17:44:46 -0700862 /*
Carl Shapiro2c81bdc2010-09-07 16:19:01 -0700863 * We have exceeded the allocation threshold. Wake up the
Carl Shapiroec47e2e2010-07-01 17:44:46 -0700864 * garbage collector.
865 */
866 dvmSignalCond(&gHs->gcThreadCond);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800867 }
868 return ptr;
869}
870
871/* Remove any hard limits, try to allocate, and shrink back down.
872 * Last resort when trying to allocate an object.
873 */
874static void *
875heapAllocAndGrow(HeapSource *hs, Heap *heap, size_t n)
876{
877 void *ptr;
878 size_t max;
879
880 /* Grow as much as possible, but don't let the real footprint
Carl Shapiroe7bdd8b2010-12-17 15:34:52 -0800881 * go over the absolute max.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800882 */
883 max = heap->absoluteMaxSize;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800884
Carl Shapiroe7bdd8b2010-12-17 15:34:52 -0800885 mspace_set_max_allowed_footprint(heap->msp, max);
886 ptr = dvmHeapSourceAlloc(n);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800887
Carl Shapiroe7bdd8b2010-12-17 15:34:52 -0800888 /* Shrink back down as small as possible. Our caller may
889 * readjust max_allowed to a more appropriate value.
890 */
891 mspace_set_max_allowed_footprint(heap->msp,
892 mspace_footprint(heap->msp));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800893 return ptr;
894}
895
896/*
897 * Allocates <n> bytes of zeroed data, growing as much as possible
898 * if necessary.
899 */
900void *
901dvmHeapSourceAllocAndGrow(size_t n)
902{
903 HeapSource *hs = gHs;
904 Heap *heap;
905 void *ptr;
906 size_t oldIdealSize;
907
908 HS_BOILERPLATE();
909 heap = hs2heap(hs);
910
911 ptr = dvmHeapSourceAlloc(n);
912 if (ptr != NULL) {
913 return ptr;
914 }
915
916 oldIdealSize = hs->idealSize;
917 if (softLimited(hs)) {
918 /* We're soft-limited. Try removing the soft limit to
919 * see if we can allocate without actually growing.
920 */
Carl Shapiro2c81bdc2010-09-07 16:19:01 -0700921 hs->softLimit = SIZE_MAX;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800922 ptr = dvmHeapSourceAlloc(n);
923 if (ptr != NULL) {
924 /* Removing the soft limit worked; fix things up to
925 * reflect the new effective ideal size.
926 */
927 snapIdealFootprint();
928 return ptr;
929 }
Carl Shapiro2c81bdc2010-09-07 16:19:01 -0700930 // softLimit intentionally left at SIZE_MAX.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800931 }
932
933 /* We're not soft-limited. Grow the heap to satisfy the request.
934 * If this call fails, no footprints will have changed.
935 */
936 ptr = heapAllocAndGrow(hs, heap, n);
937 if (ptr != NULL) {
938 /* The allocation succeeded. Fix up the ideal size to
939 * reflect any footprint modifications that had to happen.
940 */
941 snapIdealFootprint();
942 } else {
943 /* We just couldn't do it. Restore the original ideal size,
944 * fixing up softLimit if necessary.
945 */
946 setIdealFootprint(oldIdealSize);
947 }
948 return ptr;
949}
950
951/*
Carl Shapiro8881a802010-08-10 15:55:45 -0700952 * Frees the first numPtrs objects in the ptrs list and returns the
953 * amount of reclaimed storage. The list must contain addresses all in
954 * the same mspace, and must be in increasing order. This implies that
955 * there are no duplicates, and no entries are NULL.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800956 */
Carl Shapiro8881a802010-08-10 15:55:45 -0700957size_t dvmHeapSourceFreeList(size_t numPtrs, void **ptrs)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800958{
959 Heap *heap;
Carl Shapiro8881a802010-08-10 15:55:45 -0700960 size_t numBytes;
Barry Hayesdde8ab02009-05-20 12:10:36 -0700961
962 HS_BOILERPLATE();
963
964 if (numPtrs == 0) {
Carl Shapiro8881a802010-08-10 15:55:45 -0700965 return 0;
Barry Hayesdde8ab02009-05-20 12:10:36 -0700966 }
967
968 assert(ptrs != NULL);
969 assert(*ptrs != NULL);
970 heap = ptr2heap(gHs, *ptrs);
Carl Shapiro8881a802010-08-10 15:55:45 -0700971 numBytes = 0;
Barry Hayesdde8ab02009-05-20 12:10:36 -0700972 if (heap != NULL) {
973 mspace *msp = heap->msp;
974 // Calling mspace_free on shared heaps disrupts sharing too
975 // much. For heap[0] -- the 'active heap' -- we call
976 // mspace_free, but on the other heaps we only do some
977 // accounting.
978 if (heap == gHs->heaps) {
979 // mspace_merge_objects takes two allocated objects, and
980 // if the second immediately follows the first, will merge
981 // them, returning a larger object occupying the same
982 // memory. This is a local operation, and doesn't require
983 // dlmalloc to manipulate any freelists. It's pretty
984 // inexpensive compared to free().
985
986 // ptrs is an array of objects all in memory order, and if
987 // client code has been allocating lots of short-lived
988 // objects, this is likely to contain runs of objects all
989 // now garbage, and thus highly amenable to this optimization.
990
991 // Unroll the 0th iteration around the loop below,
992 // countFree ptrs[0] and initializing merged.
993 assert(ptrs[0] != NULL);
994 assert(ptr2heap(gHs, ptrs[0]) == heap);
Carl Shapiro8881a802010-08-10 15:55:45 -0700995 countFree(heap, ptrs[0], &numBytes);
Barry Hayesdde8ab02009-05-20 12:10:36 -0700996 void *merged = ptrs[0];
997
998 size_t i;
999 for (i = 1; i < numPtrs; i++) {
1000 assert(merged != NULL);
1001 assert(ptrs[i] != NULL);
1002 assert((intptr_t)merged < (intptr_t)ptrs[i]);
1003 assert(ptr2heap(gHs, ptrs[i]) == heap);
Carl Shapiro8881a802010-08-10 15:55:45 -07001004 countFree(heap, ptrs[i], &numBytes);
Barry Hayesdde8ab02009-05-20 12:10:36 -07001005 // Try to merge. If it works, merged now includes the
1006 // memory of ptrs[i]. If it doesn't, free merged, and
1007 // see if ptrs[i] starts a new run of adjacent
1008 // objects to merge.
1009 if (mspace_merge_objects(msp, merged, ptrs[i]) == NULL) {
1010 mspace_free(msp, merged);
1011 merged = ptrs[i];
1012 }
1013 }
1014 assert(merged != NULL);
1015 mspace_free(msp, merged);
1016 } else {
1017 // This is not an 'active heap'. Only do the accounting.
1018 size_t i;
1019 for (i = 0; i < numPtrs; i++) {
1020 assert(ptrs[i] != NULL);
1021 assert(ptr2heap(gHs, ptrs[i]) == heap);
Carl Shapiro8881a802010-08-10 15:55:45 -07001022 countFree(heap, ptrs[i], &numBytes);
Barry Hayesdde8ab02009-05-20 12:10:36 -07001023 }
1024 }
1025 }
Carl Shapiro8881a802010-08-10 15:55:45 -07001026 return numBytes;
Barry Hayesdde8ab02009-05-20 12:10:36 -07001027}
1028
1029/*
Barry Hayes364f9d92010-06-11 16:12:47 -07001030 * Returns true iff <ptr> is in the heap source.
1031 */
1032bool
1033dvmHeapSourceContainsAddress(const void *ptr)
1034{
1035 HS_BOILERPLATE();
1036
1037 return (dvmHeapBitmapCoversAddress(&gHs->liveBits, ptr));
1038}
1039
1040/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001041 * Returns true iff <ptr> was allocated from the heap source.
1042 */
1043bool
1044dvmHeapSourceContains(const void *ptr)
1045{
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001046 HS_BOILERPLATE();
1047
Barry Hayes364f9d92010-06-11 16:12:47 -07001048 if (dvmHeapSourceContainsAddress(ptr)) {
Carl Shapirod77f7fd2010-04-05 19:23:31 -07001049 return dvmHeapBitmapIsObjectBitSet(&gHs->liveBits, ptr) != 0;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001050 }
1051 return false;
1052}
1053
1054/*
1055 * Returns the value of the requested flag.
1056 */
1057bool
1058dvmHeapSourceGetPtrFlag(const void *ptr, enum HeapSourcePtrFlag flag)
1059{
1060 if (ptr == NULL) {
1061 return false;
1062 }
1063
1064 if (flag == HS_CONTAINS) {
1065 return dvmHeapSourceContains(ptr);
1066 } else if (flag == HS_ALLOCATED_IN_ZYGOTE) {
1067 HeapSource *hs = gHs;
1068
1069 HS_BOILERPLATE();
1070
1071 if (hs->sawZygote) {
1072 Heap *heap;
1073
1074 heap = ptr2heap(hs, ptr);
1075 if (heap != NULL) {
1076 /* If the object is not in the active heap, we assume that
1077 * it was allocated as part of zygote.
1078 */
1079 return heap != hs->heaps;
1080 }
1081 }
1082 /* The pointer is outside of any known heap, or we are not
1083 * running in zygote mode.
1084 */
1085 return false;
1086 }
1087
1088 return false;
1089}
1090
1091/*
1092 * Returns the number of usable bytes in an allocated chunk; the size
1093 * may be larger than the size passed to dvmHeapSourceAlloc().
1094 */
1095size_t
1096dvmHeapSourceChunkSize(const void *ptr)
1097{
1098 Heap *heap;
1099
1100 HS_BOILERPLATE();
1101
1102 heap = ptr2heap(gHs, ptr);
1103 if (heap != NULL) {
1104 return mspace_usable_size(heap->msp, ptr);
1105 }
1106 return 0;
1107}
1108
1109/*
1110 * Returns the number of bytes that the heap source has allocated
1111 * from the system using sbrk/mmap, etc.
1112 *
1113 * Caller must hold the heap lock.
1114 */
1115size_t
1116dvmHeapSourceFootprint()
1117{
1118 HS_BOILERPLATE();
1119
1120//TODO: include size of bitmaps?
1121 return oldHeapOverhead(gHs, true);
1122}
1123
1124/*
Carl Shapiroe7bdd8b2010-12-17 15:34:52 -08001125 * Return the real bytes used by old heaps plus the soft usage of the
1126 * current heap. When a soft limit is in effect, this is effectively
1127 * what it's compared against (though, in practice, it only looks at
1128 * the current heap).
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001129 */
1130static size_t
1131getSoftFootprint(bool includeActive)
1132{
1133 HeapSource *hs = gHs;
1134 size_t ret;
1135
1136 HS_BOILERPLATE();
1137
Carl Shapiroe7bdd8b2010-12-17 15:34:52 -08001138 ret = oldHeapOverhead(hs, false);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001139 if (includeActive) {
1140 ret += hs->heaps[0].bytesAllocated;
1141 }
1142
1143 return ret;
1144}
1145
1146/*
1147 * Gets the maximum number of bytes that the heap source is allowed
1148 * to allocate from the system.
1149 */
1150size_t
1151dvmHeapSourceGetIdealFootprint()
1152{
1153 HeapSource *hs = gHs;
1154
1155 HS_BOILERPLATE();
1156
1157 return hs->idealSize;
1158}
1159
1160/*
1161 * Sets the soft limit, handling any necessary changes to the allowed
1162 * footprint of the active heap.
1163 */
1164static void
1165setSoftLimit(HeapSource *hs, size_t softLimit)
1166{
1167 /* Compare against the actual footprint, rather than the
1168 * max_allowed, because the heap may not have grown all the
1169 * way to the allowed size yet.
1170 */
Barry Hayes06f254e2009-12-16 16:51:04 -08001171 mspace msp = hs->heaps[0].msp;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001172 size_t currentHeapSize = mspace_footprint(msp);
1173 if (softLimit < currentHeapSize) {
1174 /* Don't let the heap grow any more, and impose a soft limit.
1175 */
1176 mspace_set_max_allowed_footprint(msp, currentHeapSize);
1177 hs->softLimit = softLimit;
1178 } else {
1179 /* Let the heap grow to the requested max, and remove any
1180 * soft limit, if set.
1181 */
1182 mspace_set_max_allowed_footprint(msp, softLimit);
Carl Shapiro2c81bdc2010-09-07 16:19:01 -07001183 hs->softLimit = SIZE_MAX;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001184 }
1185}
1186
1187/*
1188 * Sets the maximum number of bytes that the heap source is allowed
1189 * to allocate from the system. Clamps to the appropriate maximum
1190 * value.
1191 */
1192static void
1193setIdealFootprint(size_t max)
1194{
1195 HeapSource *hs = gHs;
1196#if DEBUG_HEAP_SOURCE
1197 HeapSource oldHs = *hs;
Barry Hayes06f254e2009-12-16 16:51:04 -08001198 mspace msp = hs->heaps[0].msp;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001199 size_t oldAllowedFootprint =
1200 mspace_max_allowed_footprint(msp);
1201#endif
1202
1203 HS_BOILERPLATE();
1204
1205 if (max > hs->absoluteMaxSize) {
1206 LOGI_HEAP("Clamp target GC heap from %zd.%03zdMB to %u.%03uMB\n",
1207 FRACTIONAL_MB(max),
1208 FRACTIONAL_MB(hs->absoluteMaxSize));
1209 max = hs->absoluteMaxSize;
1210 } else if (max < hs->minimumSize) {
1211 max = hs->minimumSize;
1212 }
1213
1214 /* Convert max into a size that applies to the active heap.
Carl Shapiroe7bdd8b2010-12-17 15:34:52 -08001215 * Old heaps will count against the ideal size.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001216 */
1217 size_t overhead = getSoftFootprint(false);
1218 size_t activeMax;
1219 if (overhead < max) {
1220 activeMax = max - overhead;
1221 } else {
1222 activeMax = 0;
1223 }
1224
1225 setSoftLimit(hs, activeMax);
1226 hs->idealSize = max;
1227
1228 HSTRACE("IDEAL %zd->%zd (%d), soft %zd->%zd (%d), allowed %zd->%zd (%d), "
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001229 oldHs.idealSize, hs->idealSize, hs->idealSize - oldHs.idealSize,
1230 oldHs.softLimit, hs->softLimit, hs->softLimit - oldHs.softLimit,
1231 oldAllowedFootprint, mspace_max_allowed_footprint(msp),
Carl Shapiroe7bdd8b2010-12-17 15:34:52 -08001232 mspace_max_allowed_footprint(msp) - oldAllowedFootprint);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001233
1234}
1235
1236/*
1237 * Make the ideal footprint equal to the current footprint.
1238 */
1239static void
1240snapIdealFootprint()
1241{
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001242 HS_BOILERPLATE();
1243
1244 setIdealFootprint(getSoftFootprint(true));
1245}
1246
1247/*
1248 * Gets the current ideal heap utilization, represented as a number
1249 * between zero and one.
1250 */
1251float dvmGetTargetHeapUtilization()
1252{
1253 HeapSource *hs = gHs;
1254
1255 HS_BOILERPLATE();
1256
1257 return (float)hs->targetUtilization / (float)HEAP_UTILIZATION_MAX;
1258}
1259
1260/*
1261 * Sets the new ideal heap utilization, represented as a number
1262 * between zero and one.
1263 */
1264void dvmSetTargetHeapUtilization(float newTarget)
1265{
1266 HeapSource *hs = gHs;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001267
1268 HS_BOILERPLATE();
1269
1270 /* Clamp it to a reasonable range.
1271 */
1272 // TODO: This may need some tuning.
1273 if (newTarget < 0.2) {
1274 newTarget = 0.2;
1275 } else if (newTarget > 0.8) {
1276 newTarget = 0.8;
1277 }
1278
1279 hs->targetUtilization =
1280 (size_t)(newTarget * (float)HEAP_UTILIZATION_MAX);
Carl Shapirode750892010-06-08 16:37:12 -07001281 LOGV("Set heap target utilization to %zd/%d (%f)\n",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001282 hs->targetUtilization, HEAP_UTILIZATION_MAX, newTarget);
1283}
1284
1285/*
1286 * If set is true, sets the new minimum heap size to size; always
1287 * returns the current (or previous) size. If size is negative,
1288 * removes the current minimum constraint (if present).
1289 */
1290size_t
1291dvmMinimumHeapSize(size_t size, bool set)
1292{
1293 HeapSource *hs = gHs;
1294 size_t oldMinimumSize;
1295
1296 /* gHs caches an entry in gDvm.gcHeap; we need to hold the
1297 * heap lock if we're going to look at it. We also need the
1298 * lock for the call to setIdealFootprint().
1299 */
1300 dvmLockHeap();
1301
1302 HS_BOILERPLATE();
1303
1304 oldMinimumSize = hs->minimumSize;
1305
1306 if (set) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001307 if (size > hs->absoluteMaxSize) {
1308 size = hs->absoluteMaxSize;
1309 }
1310 hs->minimumSize = size;
1311 if (size > hs->idealSize) {
1312 /* Force a snap to the minimum value, which we just set
1313 * and which setIdealFootprint() will take into consideration.
1314 */
1315 setIdealFootprint(hs->idealSize);
1316 }
1317 /* Otherwise we'll just keep it in mind the next time
1318 * setIdealFootprint() is called.
1319 */
1320 }
1321
1322 dvmUnlockHeap();
1323
1324 return oldMinimumSize;
1325}
1326
1327/*
1328 * Given the size of a live set, returns the ideal heap size given
1329 * the current target utilization and MIN/MAX values.
1330 *
1331 * targetUtilization is in the range 1..HEAP_UTILIZATION_MAX.
1332 */
1333static size_t
Carl Shapiro98389d02010-02-14 23:11:47 -08001334getUtilizationTarget(size_t liveSize, size_t targetUtilization)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001335{
1336 size_t targetSize;
1337
1338 /* Use the current target utilization ratio to determine the
1339 * ideal heap size based on the size of the live set.
1340 */
1341 targetSize = (liveSize / targetUtilization) * HEAP_UTILIZATION_MAX;
1342
1343 /* Cap the amount of free space, though, so we don't end up
1344 * with, e.g., 8MB of free space when the live set size hits 8MB.
1345 */
1346 if (targetSize > liveSize + HEAP_IDEAL_FREE) {
1347 targetSize = liveSize + HEAP_IDEAL_FREE;
1348 } else if (targetSize < liveSize + HEAP_MIN_FREE) {
1349 targetSize = liveSize + HEAP_MIN_FREE;
1350 }
1351 return targetSize;
1352}
1353
1354/*
1355 * Given the current contents of the active heap, increase the allowed
1356 * heap footprint to match the target utilization ratio. This
1357 * should only be called immediately after a full mark/sweep.
1358 */
1359void dvmHeapSourceGrowForUtilization()
1360{
1361 HeapSource *hs = gHs;
1362 Heap *heap;
1363 size_t targetHeapSize;
1364 size_t currentHeapUsed;
1365 size_t oldIdealSize;
1366 size_t newHeapMax;
1367 size_t overhead;
Carl Shapiro2c81bdc2010-09-07 16:19:01 -07001368 size_t freeBytes;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001369
1370 HS_BOILERPLATE();
1371 heap = hs2heap(hs);
1372
1373 /* Use the current target utilization ratio to determine the
1374 * ideal heap size based on the size of the live set.
1375 * Note that only the active heap plays any part in this.
1376 *
1377 * Avoid letting the old heaps influence the target free size,
1378 * because they may be full of objects that aren't actually
1379 * in the working set. Just look at the allocated size of
1380 * the current heap.
1381 */
1382 currentHeapUsed = heap->bytesAllocated;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001383 targetHeapSize =
Carl Shapiro98389d02010-02-14 23:11:47 -08001384 getUtilizationTarget(currentHeapUsed, hs->targetUtilization);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001385
1386 /* The ideal size includes the old heaps; add overhead so that
1387 * it can be immediately subtracted again in setIdealFootprint().
1388 * If the target heap size would exceed the max, setIdealFootprint()
1389 * will clamp it to a legal value.
1390 */
1391 overhead = getSoftFootprint(false);
1392 oldIdealSize = hs->idealSize;
1393 setIdealFootprint(targetHeapSize + overhead);
1394
Carl Shapiro2c81bdc2010-09-07 16:19:01 -07001395 freeBytes = getAllocLimit(hs);
1396 if (freeBytes < CONCURRENT_MIN_FREE) {
1397 /* Not enough free memory to allow a concurrent GC. */
1398 heap->concurrentStartBytes = SIZE_MAX;
1399 } else {
1400 heap->concurrentStartBytes = freeBytes - CONCURRENT_START;
1401 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001402 newHeapMax = mspace_max_allowed_footprint(heap->msp);
1403 if (softLimited(hs)) {
1404 LOGD_HEAP("GC old usage %zd.%zd%%; now "
1405 "%zd.%03zdMB used / %zd.%03zdMB soft max "
1406 "(%zd.%03zdMB over, "
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001407 "%zd.%03zdMB real max)\n",
1408 FRACTIONAL_PCT(currentHeapUsed, oldIdealSize),
1409 FRACTIONAL_MB(currentHeapUsed),
1410 FRACTIONAL_MB(hs->softLimit),
1411 FRACTIONAL_MB(overhead),
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001412 FRACTIONAL_MB(newHeapMax));
1413 } else {
1414 LOGD_HEAP("GC old usage %zd.%zd%%; now "
1415 "%zd.%03zdMB used / %zd.%03zdMB real max "
Carl Shapiroe7bdd8b2010-12-17 15:34:52 -08001416 "(%zd.%03zdMB over)\n",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001417 FRACTIONAL_PCT(currentHeapUsed, oldIdealSize),
1418 FRACTIONAL_MB(currentHeapUsed),
1419 FRACTIONAL_MB(newHeapMax),
Carl Shapiroe7bdd8b2010-12-17 15:34:52 -08001420 FRACTIONAL_MB(overhead));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001421 }
1422}
1423
1424/*
1425 * Return free pages to the system.
1426 * TODO: move this somewhere else, especially the native heap part.
1427 */
1428
1429static void releasePagesInRange(void *start, void *end, void *nbytes)
1430{
1431 /* Linux requires that the madvise() start address is page-aligned.
1432 * We also align the end address.
1433 */
1434 start = (void *)ALIGN_UP_TO_PAGE_SIZE(start);
Andy McFadden96516932009-10-28 17:39:02 -07001435 end = (void *)((size_t)end & ~(SYSTEM_PAGE_SIZE - 1));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001436 if (start < end) {
1437 size_t length = (char *)end - (char *)start;
1438 madvise(start, length, MADV_DONTNEED);
1439 *(size_t *)nbytes += length;
1440 }
1441}
1442
1443/*
1444 * Return unused memory to the system if possible.
1445 */
1446void
1447dvmHeapSourceTrim(size_t bytesTrimmed[], size_t arrayLen)
1448{
1449 HeapSource *hs = gHs;
1450 size_t nativeBytes, heapBytes;
1451 size_t i;
1452
1453 HS_BOILERPLATE();
1454
1455 assert(arrayLen >= hs->numHeaps);
1456
1457 heapBytes = 0;
1458 for (i = 0; i < hs->numHeaps; i++) {
1459 Heap *heap = &hs->heaps[i];
1460
1461 /* Return the wilderness chunk to the system.
1462 */
1463 mspace_trim(heap->msp, 0);
1464
1465 /* Return any whole free pages to the system.
1466 */
1467 bytesTrimmed[i] = 0;
Carl Shapirode750892010-06-08 16:37:12 -07001468 mspace_walk_free_pages(heap->msp, releasePagesInRange,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001469 &bytesTrimmed[i]);
1470 heapBytes += bytesTrimmed[i];
1471 }
1472
1473 /* Same for the native heap.
1474 */
1475 dlmalloc_trim(0);
1476 nativeBytes = 0;
1477 dlmalloc_walk_free_pages(releasePagesInRange, &nativeBytes);
1478
1479 LOGD_HEAP("madvised %zd (GC) + %zd (native) = %zd total bytes\n",
1480 heapBytes, nativeBytes, heapBytes + nativeBytes);
1481}
1482
1483/*
1484 * Walks over the heap source and passes every allocated and
1485 * free chunk to the callback.
1486 */
1487void
1488dvmHeapSourceWalk(void(*callback)(const void *chunkptr, size_t chunklen,
1489 const void *userptr, size_t userlen,
1490 void *arg),
1491 void *arg)
1492{
1493 HeapSource *hs = gHs;
1494 size_t i;
1495
1496 HS_BOILERPLATE();
1497
1498 /* Walk the heaps from oldest to newest.
1499 */
1500//TODO: do this in address order
1501 for (i = hs->numHeaps; i > 0; --i) {
1502 mspace_walk_heap(hs->heaps[i-1].msp, callback, arg);
1503 }
1504}
1505
1506/*
1507 * Gets the number of heaps available in the heap source.
1508 *
1509 * Caller must hold the heap lock, because gHs caches a field
1510 * in gDvm.gcHeap.
1511 */
1512size_t
1513dvmHeapSourceGetNumHeaps()
1514{
1515 HeapSource *hs = gHs;
1516
1517 HS_BOILERPLATE();
1518
1519 return hs->numHeaps;
1520}
1521
Carl Shapirod25566d2010-03-11 20:39:47 -08001522void *dvmHeapSourceGetImmuneLimit(GcMode mode)
1523{
1524 if (mode == GC_PARTIAL) {
1525 return hs2heap(gHs)->base;
1526 } else {
1527 return NULL;
1528 }
1529}