blob: ed58d50213c38138096900f40133090b9ff85b9c [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
178 /* External allocation count.
179 */
180 size_t externalBytesAllocated;
181
182 /* The maximum number of external bytes that may be allocated.
183 */
184 size_t externalLimit;
185
186 /* True if zygote mode was active when the HeapSource was created.
187 */
188 bool sawZygote;
Carl Shapiroa199eb72010-02-09 16:26:30 -0800189
190 /*
191 * The base address of the virtual memory reservation.
192 */
193 char *heapBase;
194
195 /*
196 * The length in bytes of the virtual memory reservation.
197 */
198 size_t heapLength;
Carl Shapirof373efd2010-02-19 00:46:33 -0800199
200 /*
Carl Shapirod77f7fd2010-04-05 19:23:31 -0700201 * The live object bitmap.
Carl Shapirof373efd2010-02-19 00:46:33 -0800202 */
Carl Shapirod77f7fd2010-04-05 19:23:31 -0700203 HeapBitmap liveBits;
Carl Shapirof373efd2010-02-19 00:46:33 -0800204
205 /*
206 * The mark bitmap.
207 */
208 HeapBitmap markBits;
Carl Shapiroec805ea2010-06-28 16:28:26 -0700209
210 /*
211 * State for the GC daemon.
212 */
213 bool hasGcThread;
214 pthread_t gcThread;
215 bool gcThreadShutdown;
216 pthread_mutex_t gcThreadMutex;
217 pthread_cond_t gcThreadCond;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800218};
219
220#define hs2heap(hs_) (&((hs_)->heaps[0]))
221
222/*
223 * Returns true iff a soft limit is in effect for the active heap.
224 */
225static inline bool
226softLimited(const HeapSource *hs)
227{
Carl Shapiro2c81bdc2010-09-07 16:19:01 -0700228 /* softLimit will be either SIZE_MAX or the limit for the
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800229 * active mspace. idealSize can be greater than softLimit
230 * if there is more than one heap. If there is only one
Carl Shapiro2c81bdc2010-09-07 16:19:01 -0700231 * heap, a non-SIZE_MAX softLimit should always be the same
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800232 * as idealSize.
233 */
234 return hs->softLimit <= hs->idealSize;
235}
236
237/*
Carl Shapiro2c81bdc2010-09-07 16:19:01 -0700238 * Returns approximately the maximum number of bytes allowed to be
239 * allocated from the active heap before a GC is forced.
240 */
241static size_t
242getAllocLimit(const HeapSource *hs)
243{
244 if (softLimited(hs)) {
245 return hs->softLimit;
246 } else {
247 return mspace_max_allowed_footprint(hs2heap(hs)->msp);
248 }
249}
250
251/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800252 * Returns the current footprint of all heaps. If includeActive
253 * is false, don't count the heap at index 0.
254 */
255static inline size_t
256oldHeapOverhead(const HeapSource *hs, bool includeActive)
257{
258 size_t footprint = 0;
259 size_t i;
260
261 if (includeActive) {
262 i = 0;
263 } else {
264 i = 1;
265 }
266 for (/* i = i */; i < hs->numHeaps; i++) {
267//TODO: include size of bitmaps? If so, don't use bitsLen, listen to .max
268 footprint += mspace_footprint(hs->heaps[i].msp);
269 }
270 return footprint;
271}
272
273/*
274 * Returns the heap that <ptr> could have come from, or NULL
275 * if it could not have come from any heap.
276 */
277static inline Heap *
278ptr2heap(const HeapSource *hs, const void *ptr)
279{
280 const size_t numHeaps = hs->numHeaps;
281 size_t i;
282
283//TODO: unroll this to HEAP_SOURCE_MAX_HEAP_COUNT
284 if (ptr != NULL) {
285 for (i = 0; i < numHeaps; i++) {
286 const Heap *const heap = &hs->heaps[i];
Carl Shapirof373efd2010-02-19 00:46:33 -0800287
288 if ((const char *)ptr >= heap->base && (const char *)ptr < heap->limit) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800289 return (Heap *)heap;
290 }
291 }
292 }
293 return NULL;
294}
295
296/*
297 * Functions to update heapSource->bytesAllocated when an object
298 * is allocated or freed. mspace_usable_size() will give
299 * us a much more accurate picture of heap utilization than
300 * the requested byte sizes would.
301 *
302 * These aren't exact, and should not be treated as such.
303 */
Carl Shapiroec47e2e2010-07-01 17:44:46 -0700304static void countAllocation(Heap *heap, const void *ptr, bool isObj)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800305{
Carl Shapirof373efd2010-02-19 00:46:33 -0800306 HeapSource *hs;
307
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800308 assert(heap->bytesAllocated < mspace_footprint(heap->msp));
309
310 heap->bytesAllocated += mspace_usable_size(heap->msp, ptr) +
311 HEAP_SOURCE_CHUNK_OVERHEAD;
312 if (isObj) {
313 heap->objectsAllocated++;
Carl Shapirof373efd2010-02-19 00:46:33 -0800314 hs = gDvm.gcHeap->heapSource;
Carl Shapirod77f7fd2010-04-05 19:23:31 -0700315 dvmHeapBitmapSetObjectBit(&hs->liveBits, ptr);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800316 }
317
318 assert(heap->bytesAllocated < mspace_footprint(heap->msp));
319}
320
Carl Shapiro8881a802010-08-10 15:55:45 -0700321static void countFree(Heap *heap, const void *ptr, size_t *numBytes)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800322{
Carl Shapirof373efd2010-02-19 00:46:33 -0800323 HeapSource *hs;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800324 size_t delta;
325
326 delta = mspace_usable_size(heap->msp, ptr) + HEAP_SOURCE_CHUNK_OVERHEAD;
327 assert(delta > 0);
328 if (delta < heap->bytesAllocated) {
329 heap->bytesAllocated -= delta;
330 } else {
331 heap->bytesAllocated = 0;
332 }
Carl Shapiro8881a802010-08-10 15:55:45 -0700333 hs = gDvm.gcHeap->heapSource;
334 dvmHeapBitmapClearObjectBit(&hs->liveBits, ptr);
335 if (heap->objectsAllocated > 0) {
336 heap->objectsAllocated--;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800337 }
Carl Shapiro8881a802010-08-10 15:55:45 -0700338 *numBytes += delta;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800339}
340
341static HeapSource *gHs = NULL;
342
Barry Hayes06f254e2009-12-16 16:51:04 -0800343static mspace
Carl Shapiroa199eb72010-02-09 16:26:30 -0800344createMspace(void *base, size_t startSize, size_t absoluteMaxSize)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800345{
Barry Hayes06f254e2009-12-16 16:51:04 -0800346 mspace msp;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800347
348 /* Create an unlocked dlmalloc mspace to use as
349 * a small-object heap source.
350 *
351 * We start off reserving heapSizeStart/2 bytes but
352 * letting the heap grow to heapSizeStart. This saves
353 * memory in the case where a process uses even less
354 * than the starting size.
355 */
356 LOGV_HEAP("Creating VM heap of size %u\n", startSize);
357 errno = 0;
Carl Shapiroa199eb72010-02-09 16:26:30 -0800358 msp = create_contiguous_mspace_with_base(startSize/2,
359 absoluteMaxSize, /*locked=*/false, base);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800360 if (msp != NULL) {
361 /* Don't let the heap grow past the starting size without
362 * our intervention.
363 */
364 mspace_set_max_allowed_footprint(msp, startSize);
365 } else {
366 /* There's no guarantee that errno has meaning when the call
367 * fails, but it often does.
368 */
Elliott Hughesc5f53e22010-06-11 16:13:15 -0700369 LOGE_HEAP("Can't create VM heap of size (%u,%u): %s\n",
370 startSize/2, absoluteMaxSize, strerror(errno));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800371 }
372
373 return msp;
374}
375
376static bool
Barry Hayes06f254e2009-12-16 16:51:04 -0800377addNewHeap(HeapSource *hs, mspace msp, size_t mspAbsoluteMaxSize)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800378{
379 Heap heap;
380
381 if (hs->numHeaps >= HEAP_SOURCE_MAX_HEAP_COUNT) {
382 LOGE("Attempt to create too many heaps (%zd >= %zd)\n",
383 hs->numHeaps, HEAP_SOURCE_MAX_HEAP_COUNT);
384 dvmAbort();
385 return false;
386 }
387
388 memset(&heap, 0, sizeof(heap));
389
390 if (msp != NULL) {
391 heap.msp = msp;
392 heap.absoluteMaxSize = mspAbsoluteMaxSize;
Carl Shapiro2c81bdc2010-09-07 16:19:01 -0700393 heap.concurrentStartBytes = SIZE_MAX;
Carl Shapirof373efd2010-02-19 00:46:33 -0800394 heap.base = hs->heapBase;
395 heap.limit = hs->heapBase + heap.absoluteMaxSize;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800396 } else {
Carl Shapiro88c57e12010-10-10 18:50:22 -0700397 void *sbrk0 = contiguous_mspace_sbrk0(hs->heaps[0].msp);
398 char *base = (char *)ALIGN_UP_TO_PAGE_SIZE(sbrk0);
399 size_t overhead = base - hs->heaps[0].base;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800400
Carl Shapiro88c57e12010-10-10 18:50:22 -0700401 assert(((size_t)hs->heaps[0].base & (SYSTEM_PAGE_SIZE - 1)) == 0);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800402 if (overhead + HEAP_MIN_FREE >= hs->absoluteMaxSize) {
403 LOGE_HEAP("No room to create any more heaps "
404 "(%zd overhead, %zd max)\n",
405 overhead, hs->absoluteMaxSize);
406 return false;
407 }
Carl Shapirod25566d2010-03-11 20:39:47 -0800408 hs->heaps[0].absoluteMaxSize = overhead;
Carl Shapirof373efd2010-02-19 00:46:33 -0800409 hs->heaps[0].limit = base;
Carl Shapiro88c57e12010-10-10 18:50:22 -0700410 heap.absoluteMaxSize = hs->absoluteMaxSize - overhead;
Carl Shapiroa199eb72010-02-09 16:26:30 -0800411 heap.msp = createMspace(base, HEAP_MIN_FREE, heap.absoluteMaxSize);
Carl Shapiro2c81bdc2010-09-07 16:19:01 -0700412 heap.concurrentStartBytes = HEAP_MIN_FREE - CONCURRENT_START;
Carl Shapirof373efd2010-02-19 00:46:33 -0800413 heap.base = base;
414 heap.limit = heap.base + heap.absoluteMaxSize;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800415 if (heap.msp == NULL) {
416 return false;
417 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800418 }
419
420 /* Don't let the soon-to-be-old heap grow any further.
421 */
422 if (hs->numHeaps > 0) {
Barry Hayes06f254e2009-12-16 16:51:04 -0800423 mspace msp = hs->heaps[0].msp;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800424 mspace_set_max_allowed_footprint(msp, mspace_footprint(msp));
425 }
426
427 /* Put the new heap in the list, at heaps[0].
428 * Shift existing heaps down.
429 */
430 memmove(&hs->heaps[1], &hs->heaps[0], hs->numHeaps * sizeof(hs->heaps[0]));
431 hs->heaps[0] = heap;
432 hs->numHeaps++;
433
434 return true;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800435}
436
437/*
Carl Shapiroec805ea2010-06-28 16:28:26 -0700438 * The garbage collection daemon. Initiates a concurrent collection
439 * when signaled.
440 */
441static void *gcDaemonThread(void* arg)
442{
443 dvmChangeStatus(NULL, THREAD_VMWAIT);
444 dvmLockMutex(&gHs->gcThreadMutex);
445 while (gHs->gcThreadShutdown != true) {
446 dvmWaitCond(&gHs->gcThreadCond, &gHs->gcThreadMutex);
447 dvmLockHeap();
448 dvmChangeStatus(NULL, THREAD_RUNNING);
449 dvmCollectGarbageInternal(false, GC_CONCURRENT);
450 dvmChangeStatus(NULL, THREAD_VMWAIT);
451 dvmUnlockHeap();
452 }
453 dvmChangeStatus(NULL, THREAD_RUNNING);
454 return NULL;
455}
456
457static bool gcDaemonStartup(void)
458{
459 dvmInitMutex(&gHs->gcThreadMutex);
460 pthread_cond_init(&gHs->gcThreadCond, NULL);
461 gHs->gcThreadShutdown = false;
462 gHs->hasGcThread = dvmCreateInternalThread(&gHs->gcThread, "GC",
463 gcDaemonThread, NULL);
464 return gHs->hasGcThread;
465}
466
467static void gcDaemonShutdown(void)
468{
Carl Shapirofe608772010-07-28 19:33:46 -0700469 if (gHs->hasGcThread) {
Carl Shapiroec805ea2010-06-28 16:28:26 -0700470 dvmLockMutex(&gHs->gcThreadMutex);
471 gHs->gcThreadShutdown = true;
472 dvmSignalCond(&gHs->gcThreadCond);
Carl Shapiroec805ea2010-06-28 16:28:26 -0700473 dvmUnlockMutex(&gHs->gcThreadMutex);
Carl Shapiro9e594772010-06-28 17:24:17 -0700474 pthread_join(gHs->gcThread, NULL);
Carl Shapiroec805ea2010-06-28 16:28:26 -0700475 }
476}
477
478/*
Carl Shapirofdf80522010-11-09 14:27:02 -0800479 * Create a stack big enough for the worst possible case, where the
480 * heap is perfectly full of the smallest object.
481 * TODO: be better about memory usage; use a smaller stack with
482 * overflow detection and recovery.
483 */
484static bool allocMarkStack(GcMarkStack *stack, size_t maximumSize)
485{
486 const char *name = "dalvik-mark-stack";
487 void *addr;
488
489 assert(stack != NULL);
490 stack->length = maximumSize * sizeof(Object*) /
491 (sizeof(Object) + HEAP_SOURCE_CHUNK_OVERHEAD);
492 addr = dvmAllocRegion(stack->length, PROT_READ | PROT_WRITE, name);
493 if (addr == NULL) {
494 return false;
495 }
496 stack->base = (const Object **)addr;
497 stack->limit = (const Object **)((char *)addr + stack->length);
498 stack->top = NULL;
499 madvise(stack->base, stack->length, MADV_DONTNEED);
500 return true;
501}
502
503static void freeMarkStack(GcMarkStack *stack)
504{
505 assert(stack != NULL);
506 munmap(stack->base, stack->length);
507 memset(stack, 0, sizeof(*stack));
508}
509
510/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800511 * Initializes the heap source; must be called before any other
512 * dvmHeapSource*() functions. Returns a GcHeap structure
513 * allocated from the heap source.
514 */
515GcHeap *
516dvmHeapSourceStartup(size_t startSize, size_t absoluteMaxSize)
517{
518 GcHeap *gcHeap;
519 HeapSource *hs;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800520 mspace msp;
Carl Shapiroa199eb72010-02-09 16:26:30 -0800521 size_t length;
522 void *base;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800523
524 assert(gHs == NULL);
525
526 if (startSize > absoluteMaxSize) {
527 LOGE("Bad heap parameters (start=%d, max=%d)\n",
528 startSize, absoluteMaxSize);
529 return NULL;
530 }
531
Carl Shapiroa199eb72010-02-09 16:26:30 -0800532 /*
533 * Allocate a contiguous region of virtual memory to subdivided
534 * among the heaps managed by the garbage collector.
535 */
536 length = ALIGN_UP_TO_PAGE_SIZE(absoluteMaxSize);
Barry Hayes6e5cf602010-06-22 12:32:59 -0700537 base = dvmAllocRegion(length, PROT_NONE, "dalvik-heap");
538 if (base == NULL) {
Carl Shapiroa199eb72010-02-09 16:26:30 -0800539 return NULL;
540 }
Carl Shapiroa199eb72010-02-09 16:26:30 -0800541
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800542 /* Create an unlocked dlmalloc mspace to use as
543 * the small object heap source.
544 */
Carl Shapiroa199eb72010-02-09 16:26:30 -0800545 msp = createMspace(base, startSize, absoluteMaxSize);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800546 if (msp == NULL) {
Carl Shapiroa199eb72010-02-09 16:26:30 -0800547 goto fail;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800548 }
549
550 /* Allocate a descriptor from the heap we just created.
551 */
552 gcHeap = mspace_malloc(msp, sizeof(*gcHeap));
553 if (gcHeap == NULL) {
554 LOGE_HEAP("Can't allocate heap descriptor\n");
555 goto fail;
556 }
557 memset(gcHeap, 0, sizeof(*gcHeap));
558
559 hs = mspace_malloc(msp, sizeof(*hs));
560 if (hs == NULL) {
561 LOGE_HEAP("Can't allocate heap source\n");
562 goto fail;
563 }
564 memset(hs, 0, sizeof(*hs));
565
566 hs->targetUtilization = DEFAULT_HEAP_UTILIZATION;
567 hs->minimumSize = 0;
568 hs->startSize = startSize;
569 hs->absoluteMaxSize = absoluteMaxSize;
570 hs->idealSize = startSize;
Carl Shapiro2c81bdc2010-09-07 16:19:01 -0700571 hs->softLimit = SIZE_MAX; // no soft limit at first
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800572 hs->numHeaps = 0;
573 hs->sawZygote = gDvm.zygote;
Carl Shapiroec805ea2010-06-28 16:28:26 -0700574 hs->hasGcThread = false;
Carl Shapiroa199eb72010-02-09 16:26:30 -0800575 hs->heapBase = base;
576 hs->heapLength = length;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800577 if (!addNewHeap(hs, msp, absoluteMaxSize)) {
578 LOGE_HEAP("Can't add initial heap\n");
579 goto fail;
580 }
Carl Shapirod77f7fd2010-04-05 19:23:31 -0700581 if (!dvmHeapBitmapInit(&hs->liveBits, base, length, "dalvik-bitmap-1")) {
582 LOGE_HEAP("Can't create liveBits\n");
Carl Shapirof373efd2010-02-19 00:46:33 -0800583 goto fail;
584 }
585 if (!dvmHeapBitmapInit(&hs->markBits, base, length, "dalvik-bitmap-2")) {
586 LOGE_HEAP("Can't create markBits\n");
Carl Shapirod77f7fd2010-04-05 19:23:31 -0700587 dvmHeapBitmapDelete(&hs->liveBits);
Carl Shapirof373efd2010-02-19 00:46:33 -0800588 goto fail;
589 }
Carl Shapirofdf80522010-11-09 14:27:02 -0800590 if (!allocMarkStack(&gcHeap->markContext.stack, hs->absoluteMaxSize)) {
591 LOGE("Can't create markStack");
592 dvmHeapBitmapDelete(&hs->markBits);
593 dvmHeapBitmapDelete(&hs->liveBits);
594 goto fail;
595 }
Carl Shapirof373efd2010-02-19 00:46:33 -0800596 gcHeap->markContext.bitmap = &hs->markBits;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800597 gcHeap->heapSource = hs;
598
599 countAllocation(hs2heap(hs), gcHeap, false);
600 countAllocation(hs2heap(hs), hs, false);
601
602 gHs = hs;
603 return gcHeap;
604
605fail:
Carl Shapiroa199eb72010-02-09 16:26:30 -0800606 munmap(base, length);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800607 return NULL;
608}
609
Carl Shapiroec805ea2010-06-28 16:28:26 -0700610bool dvmHeapSourceStartupAfterZygote(void)
611{
612 return gDvm.concurrentMarkSweep ? gcDaemonStartup() : true;
613}
614
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800615/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800616 * This is called while in zygote mode, right before we fork() for the
617 * first time. We create a heap for all future zygote process allocations,
618 * in an attempt to avoid touching pages in the zygote heap. (This would
619 * probably be unnecessary if we had a compacting GC -- the source of our
620 * troubles is small allocations filling in the gaps from larger ones.)
621 */
622bool
623dvmHeapSourceStartupBeforeFork()
624{
625 HeapSource *hs = gHs; // use a local to avoid the implicit "volatile"
626
627 HS_BOILERPLATE();
628
629 assert(gDvm.zygote);
630
631 if (!gDvm.newZygoteHeapAllocated) {
632 /* Create a new heap for post-fork zygote allocations. We only
633 * try once, even if it fails.
634 */
Andy McFaddendced7942009-11-17 13:13:34 -0800635 LOGV("Splitting out new zygote heap\n");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800636 gDvm.newZygoteHeapAllocated = true;
637 return addNewHeap(hs, NULL, 0);
638 }
639 return true;
640}
641
Carl Shapiroec805ea2010-06-28 16:28:26 -0700642void dvmHeapSourceThreadShutdown(void)
643{
Carl Shapirofe608772010-07-28 19:33:46 -0700644 if (gDvm.gcHeap != NULL && gDvm.concurrentMarkSweep) {
Carl Shapirod7de4502010-07-15 11:26:26 -0700645 gcDaemonShutdown();
646 }
Carl Shapiroec805ea2010-06-28 16:28:26 -0700647}
648
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800649/*
Carl Shapiroa199eb72010-02-09 16:26:30 -0800650 * Tears down the entire GcHeap structure and all of the substructures
651 * attached to it. This call has the side effect of setting the given
652 * gcHeap pointer and gHs to NULL.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800653 */
654void
Carl Shapiroa199eb72010-02-09 16:26:30 -0800655dvmHeapSourceShutdown(GcHeap **gcHeap)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800656{
Carl Shapiroa199eb72010-02-09 16:26:30 -0800657 if (*gcHeap != NULL && (*gcHeap)->heapSource != NULL) {
Carl Shapirofdf80522010-11-09 14:27:02 -0800658 HeapSource *hs = (*gcHeap)->heapSource;
Carl Shapiroa199eb72010-02-09 16:26:30 -0800659 assert((char *)*gcHeap >= hs->heapBase);
660 assert((char *)*gcHeap < hs->heapBase + hs->heapLength);
Carl Shapirod77f7fd2010-04-05 19:23:31 -0700661 dvmHeapBitmapDelete(&hs->liveBits);
Carl Shapirof373efd2010-02-19 00:46:33 -0800662 dvmHeapBitmapDelete(&hs->markBits);
Carl Shapirofdf80522010-11-09 14:27:02 -0800663 freeMarkStack(&(*gcHeap)->markContext.stack);
Carl Shapiroa199eb72010-02-09 16:26:30 -0800664 munmap(hs->heapBase, hs->heapLength);
665 gHs = NULL;
666 *gcHeap = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800667 }
668}
669
670/*
Barry Hayesb874ab92010-07-14 08:13:18 -0700671 * Gets the begining of the allocation for the HeapSource.
672 */
673void *dvmHeapSourceGetBase(void)
674{
675 return gHs->heapBase;
676}
677
678/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800679 * Returns the requested value. If the per-heap stats are requested, fill
680 * them as well.
681 *
682 * Caller must hold the heap lock.
683 */
684size_t
685dvmHeapSourceGetValue(enum HeapSourceValueSpec spec, size_t perHeapStats[],
686 size_t arrayLen)
687{
688 HeapSource *hs = gHs;
689 size_t value = 0;
690 size_t total = 0;
691 size_t i;
692
693 HS_BOILERPLATE();
694
695 switch (spec) {
696 case HS_EXTERNAL_BYTES_ALLOCATED:
697 return hs->externalBytesAllocated;
698 case HS_EXTERNAL_LIMIT:
699 return hs->externalLimit;
700 default:
701 // look at all heaps.
702 ;
703 }
704
705 assert(arrayLen >= hs->numHeaps || perHeapStats == NULL);
706 for (i = 0; i < hs->numHeaps; i++) {
707 Heap *const heap = &hs->heaps[i];
708
709 switch (spec) {
710 case HS_FOOTPRINT:
711 value = mspace_footprint(heap->msp);
712 break;
713 case HS_ALLOWED_FOOTPRINT:
714 value = mspace_max_allowed_footprint(heap->msp);
715 break;
716 case HS_BYTES_ALLOCATED:
717 value = heap->bytesAllocated;
718 break;
719 case HS_OBJECTS_ALLOCATED:
720 value = heap->objectsAllocated;
721 break;
722 default:
723 // quiet gcc
724 break;
725 }
726 if (perHeapStats) {
727 perHeapStats[i] = value;
728 }
729 total += value;
730 }
731 return total;
732}
733
Carl Shapirof373efd2010-02-19 00:46:33 -0800734static void aliasBitmap(HeapBitmap *dst, HeapBitmap *src,
735 uintptr_t base, uintptr_t max) {
736 size_t offset;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800737
Carl Shapirof373efd2010-02-19 00:46:33 -0800738 dst->base = base;
739 dst->max = max;
Barry Hayes73f3e6f2010-07-15 08:58:10 -0700740 dst->bitsLen = HB_OFFSET_TO_BYTE_INDEX(max - base) + sizeof(dst->bits);
741 /* The exclusive limit from bitsLen is greater than the inclusive max. */
742 assert(base + HB_MAX_OFFSET(dst) > max);
Barry Hayes8a0b5232010-07-21 11:22:04 -0700743 /* The exclusive limit is at most one word of bits beyond max. */
744 assert((base + HB_MAX_OFFSET(dst)) - max <=
Barry Hayes73f3e6f2010-07-15 08:58:10 -0700745 HB_OBJECT_ALIGNMENT * HB_BITS_PER_WORD);
Carl Shapirod25566d2010-03-11 20:39:47 -0800746 dst->allocLen = dst->bitsLen;
Carl Shapirof373efd2010-02-19 00:46:33 -0800747 offset = base - src->base;
748 assert(HB_OFFSET_TO_MASK(offset) == 1 << 31);
749 dst->bits = &src->bits[HB_OFFSET_TO_INDEX(offset)];
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800750}
751
752/*
Carl Shapirof373efd2010-02-19 00:46:33 -0800753 * Initializes a vector of object and mark bits to the object and mark
Barry Hayese168ebd2010-05-07 09:19:46 -0700754 * bits of each heap. The bits are aliased to the heapsource
Carl Shapirof373efd2010-02-19 00:46:33 -0800755 * object and mark bitmaps. This routine is used by the sweep code
756 * which needs to free each object in the correct heap.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800757 */
Carl Shapirod77f7fd2010-04-05 19:23:31 -0700758void dvmHeapSourceGetObjectBitmaps(HeapBitmap liveBits[], HeapBitmap markBits[],
Carl Shapirof373efd2010-02-19 00:46:33 -0800759 size_t numHeaps)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800760{
761 HeapSource *hs = gHs;
Carl Shapirof373efd2010-02-19 00:46:33 -0800762 uintptr_t base, max;
Carl Shapiroe3c01da2010-05-20 22:54:18 -0700763 size_t i;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800764
765 HS_BOILERPLATE();
766
Carl Shapirof373efd2010-02-19 00:46:33 -0800767 assert(numHeaps == hs->numHeaps);
768 for (i = 0; i < hs->numHeaps; ++i) {
769 base = (uintptr_t)hs->heaps[i].base;
Barry Hayes73f3e6f2010-07-15 08:58:10 -0700770 /* -1 because limit is exclusive but max is inclusive. */
Carl Shapiroe6a1b4d2010-08-17 18:33:56 -0700771 max = MIN((uintptr_t)hs->heaps[i].limit - 1, hs->markBits.max);
Carl Shapirod77f7fd2010-04-05 19:23:31 -0700772 aliasBitmap(&liveBits[i], &hs->liveBits, base, max);
Carl Shapirof373efd2010-02-19 00:46:33 -0800773 aliasBitmap(&markBits[i], &hs->markBits, base, max);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800774 }
Carl Shapirof373efd2010-02-19 00:46:33 -0800775}
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800776
Barry Hayes962adba2010-03-17 12:12:39 -0700777/*
778 * Get the bitmap representing all live objects.
779 */
Carl Shapiroec805ea2010-06-28 16:28:26 -0700780HeapBitmap *dvmHeapSourceGetLiveBits(void)
Barry Hayes962adba2010-03-17 12:12:39 -0700781{
782 HS_BOILERPLATE();
783
Carl Shapirod77f7fd2010-04-05 19:23:31 -0700784 return &gHs->liveBits;
Barry Hayes962adba2010-03-17 12:12:39 -0700785}
786
Carl Shapirof373efd2010-02-19 00:46:33 -0800787void dvmHeapSourceSwapBitmaps(void)
788{
789 HeapBitmap tmp;
Barry Hayes81010a42010-07-19 14:07:01 -0700790
Carl Shapirod77f7fd2010-04-05 19:23:31 -0700791 tmp = gHs->liveBits;
792 gHs->liveBits = gHs->markBits;
Carl Shapirof373efd2010-02-19 00:46:33 -0800793 gHs->markBits = tmp;
Barry Hayes81010a42010-07-19 14:07:01 -0700794}
795
796void dvmHeapSourceZeroMarkBitmap(void)
797{
798 HS_BOILERPLATE();
799
Carl Shapirof373efd2010-02-19 00:46:33 -0800800 dvmHeapBitmapZero(&gHs->markBits);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800801}
802
Barry Hayes425848f2010-05-04 13:32:12 -0700803void dvmMarkImmuneObjects(const char *immuneLimit)
Carl Shapirod25566d2010-03-11 20:39:47 -0800804{
805 char *dst, *src;
Carl Shapiroe3c01da2010-05-20 22:54:18 -0700806 size_t i, index, length;
Carl Shapirod25566d2010-03-11 20:39:47 -0800807
808 /*
809 * Copy the contents of the live bit vector for immune object
810 * range into the mark bit vector.
811 */
Barry Hayes425848f2010-05-04 13:32:12 -0700812 /* The only values generated by dvmHeapSourceGetImmuneLimit() */
813 assert(immuneLimit == gHs->heaps[0].base ||
814 immuneLimit == NULL);
Carl Shapirod77f7fd2010-04-05 19:23:31 -0700815 assert(gHs->liveBits.base == gHs->markBits.base);
816 assert(gHs->liveBits.bitsLen == gHs->markBits.bitsLen);
Barry Hayes425848f2010-05-04 13:32:12 -0700817 /* heap[0] is never immune */
818 assert(gHs->heaps[0].base >= immuneLimit);
819 assert(gHs->heaps[0].limit > immuneLimit);
820
Carl Shapirod25566d2010-03-11 20:39:47 -0800821 for (i = 1; i < gHs->numHeaps; ++i) {
Barry Hayes425848f2010-05-04 13:32:12 -0700822 if (gHs->heaps[i].base < immuneLimit) {
823 assert(gHs->heaps[i].limit <= immuneLimit);
Barry Hayes425848f2010-05-04 13:32:12 -0700824 /* Compute the number of words to copy in the bitmap. */
825 index = HB_OFFSET_TO_INDEX(
826 (uintptr_t)gHs->heaps[i].base - gHs->liveBits.base);
827 /* Compute the starting offset in the live and mark bits. */
828 src = (char *)(gHs->liveBits.bits + index);
829 dst = (char *)(gHs->markBits.bits + index);
830 /* Compute the number of bytes of the live bitmap to copy. */
831 length = HB_OFFSET_TO_BYTE_INDEX(
832 gHs->heaps[i].limit - gHs->heaps[i].base);
833 /* Do the copy. */
834 memcpy(dst, src, length);
835 /* Make sure max points to the address of the highest set bit. */
836 if (gHs->markBits.max < (uintptr_t)gHs->heaps[i].limit) {
837 gHs->markBits.max = (uintptr_t)gHs->heaps[i].limit;
838 }
Carl Shapirod25566d2010-03-11 20:39:47 -0800839 }
840 }
841}
842
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800843/*
844 * Allocates <n> bytes of zeroed data.
845 */
846void *
847dvmHeapSourceAlloc(size_t n)
848{
849 HeapSource *hs = gHs;
850 Heap *heap;
851 void *ptr;
852
853 HS_BOILERPLATE();
854 heap = hs2heap(hs);
Carl Shapiroec47e2e2010-07-01 17:44:46 -0700855 if (heap->bytesAllocated + n > hs->softLimit) {
856 /*
857 * This allocation would push us over the soft limit; act as
858 * if the heap is full.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800859 */
860 LOGV_HEAP("softLimit of %zd.%03zdMB hit for %zd-byte allocation\n",
Carl Shapiroec47e2e2010-07-01 17:44:46 -0700861 FRACTIONAL_MB(hs->softLimit), n);
862 return NULL;
863 }
864 ptr = mspace_calloc(heap->msp, 1, n);
865 if (ptr == NULL) {
866 return NULL;
867 }
868 countAllocation(heap, ptr, true);
869 /*
870 * Check to see if a concurrent GC should be initiated.
871 */
872 if (gDvm.gcHeap->gcRunning || !hs->hasGcThread) {
873 /*
874 * The garbage collector thread is already running or has yet
875 * to be started. Do nothing.
876 */
877 return ptr;
878 }
Carl Shapiro2c81bdc2010-09-07 16:19:01 -0700879 if (heap->bytesAllocated > heap->concurrentStartBytes) {
Carl Shapiroec47e2e2010-07-01 17:44:46 -0700880 /*
Carl Shapiro2c81bdc2010-09-07 16:19:01 -0700881 * We have exceeded the allocation threshold. Wake up the
Carl Shapiroec47e2e2010-07-01 17:44:46 -0700882 * garbage collector.
883 */
884 dvmSignalCond(&gHs->gcThreadCond);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800885 }
886 return ptr;
887}
888
889/* Remove any hard limits, try to allocate, and shrink back down.
890 * Last resort when trying to allocate an object.
891 */
892static void *
893heapAllocAndGrow(HeapSource *hs, Heap *heap, size_t n)
894{
895 void *ptr;
896 size_t max;
897
898 /* Grow as much as possible, but don't let the real footprint
899 * plus external allocations go over the absolute max.
900 */
901 max = heap->absoluteMaxSize;
902 if (max > hs->externalBytesAllocated) {
903 max -= hs->externalBytesAllocated;
904
905 mspace_set_max_allowed_footprint(heap->msp, max);
906 ptr = dvmHeapSourceAlloc(n);
907
908 /* Shrink back down as small as possible. Our caller may
909 * readjust max_allowed to a more appropriate value.
910 */
911 mspace_set_max_allowed_footprint(heap->msp,
912 mspace_footprint(heap->msp));
913 } else {
914 ptr = NULL;
915 }
916
917 return ptr;
918}
919
920/*
921 * Allocates <n> bytes of zeroed data, growing as much as possible
922 * if necessary.
923 */
924void *
925dvmHeapSourceAllocAndGrow(size_t n)
926{
927 HeapSource *hs = gHs;
928 Heap *heap;
929 void *ptr;
930 size_t oldIdealSize;
931
932 HS_BOILERPLATE();
933 heap = hs2heap(hs);
934
935 ptr = dvmHeapSourceAlloc(n);
936 if (ptr != NULL) {
937 return ptr;
938 }
939
940 oldIdealSize = hs->idealSize;
941 if (softLimited(hs)) {
942 /* We're soft-limited. Try removing the soft limit to
943 * see if we can allocate without actually growing.
944 */
Carl Shapiro2c81bdc2010-09-07 16:19:01 -0700945 hs->softLimit = SIZE_MAX;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800946 ptr = dvmHeapSourceAlloc(n);
947 if (ptr != NULL) {
948 /* Removing the soft limit worked; fix things up to
949 * reflect the new effective ideal size.
950 */
951 snapIdealFootprint();
952 return ptr;
953 }
Carl Shapiro2c81bdc2010-09-07 16:19:01 -0700954 // softLimit intentionally left at SIZE_MAX.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800955 }
956
957 /* We're not soft-limited. Grow the heap to satisfy the request.
958 * If this call fails, no footprints will have changed.
959 */
960 ptr = heapAllocAndGrow(hs, heap, n);
961 if (ptr != NULL) {
962 /* The allocation succeeded. Fix up the ideal size to
963 * reflect any footprint modifications that had to happen.
964 */
965 snapIdealFootprint();
966 } else {
967 /* We just couldn't do it. Restore the original ideal size,
968 * fixing up softLimit if necessary.
969 */
970 setIdealFootprint(oldIdealSize);
971 }
972 return ptr;
973}
974
975/*
Carl Shapiro8881a802010-08-10 15:55:45 -0700976 * Frees the first numPtrs objects in the ptrs list and returns the
977 * amount of reclaimed storage. The list must contain addresses all in
978 * the same mspace, and must be in increasing order. This implies that
979 * there are no duplicates, and no entries are NULL.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800980 */
Carl Shapiro8881a802010-08-10 15:55:45 -0700981size_t dvmHeapSourceFreeList(size_t numPtrs, void **ptrs)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800982{
983 Heap *heap;
Carl Shapiro8881a802010-08-10 15:55:45 -0700984 size_t numBytes;
Barry Hayesdde8ab02009-05-20 12:10:36 -0700985
986 HS_BOILERPLATE();
987
988 if (numPtrs == 0) {
Carl Shapiro8881a802010-08-10 15:55:45 -0700989 return 0;
Barry Hayesdde8ab02009-05-20 12:10:36 -0700990 }
991
992 assert(ptrs != NULL);
993 assert(*ptrs != NULL);
994 heap = ptr2heap(gHs, *ptrs);
Carl Shapiro8881a802010-08-10 15:55:45 -0700995 numBytes = 0;
Barry Hayesdde8ab02009-05-20 12:10:36 -0700996 if (heap != NULL) {
997 mspace *msp = heap->msp;
998 // Calling mspace_free on shared heaps disrupts sharing too
999 // much. For heap[0] -- the 'active heap' -- we call
1000 // mspace_free, but on the other heaps we only do some
1001 // accounting.
1002 if (heap == gHs->heaps) {
1003 // mspace_merge_objects takes two allocated objects, and
1004 // if the second immediately follows the first, will merge
1005 // them, returning a larger object occupying the same
1006 // memory. This is a local operation, and doesn't require
1007 // dlmalloc to manipulate any freelists. It's pretty
1008 // inexpensive compared to free().
1009
1010 // ptrs is an array of objects all in memory order, and if
1011 // client code has been allocating lots of short-lived
1012 // objects, this is likely to contain runs of objects all
1013 // now garbage, and thus highly amenable to this optimization.
1014
1015 // Unroll the 0th iteration around the loop below,
1016 // countFree ptrs[0] and initializing merged.
1017 assert(ptrs[0] != NULL);
1018 assert(ptr2heap(gHs, ptrs[0]) == heap);
Carl Shapiro8881a802010-08-10 15:55:45 -07001019 countFree(heap, ptrs[0], &numBytes);
Barry Hayesdde8ab02009-05-20 12:10:36 -07001020 void *merged = ptrs[0];
1021
1022 size_t i;
1023 for (i = 1; i < numPtrs; i++) {
1024 assert(merged != NULL);
1025 assert(ptrs[i] != NULL);
1026 assert((intptr_t)merged < (intptr_t)ptrs[i]);
1027 assert(ptr2heap(gHs, ptrs[i]) == heap);
Carl Shapiro8881a802010-08-10 15:55:45 -07001028 countFree(heap, ptrs[i], &numBytes);
Barry Hayesdde8ab02009-05-20 12:10:36 -07001029 // Try to merge. If it works, merged now includes the
1030 // memory of ptrs[i]. If it doesn't, free merged, and
1031 // see if ptrs[i] starts a new run of adjacent
1032 // objects to merge.
1033 if (mspace_merge_objects(msp, merged, ptrs[i]) == NULL) {
1034 mspace_free(msp, merged);
1035 merged = ptrs[i];
1036 }
1037 }
1038 assert(merged != NULL);
1039 mspace_free(msp, merged);
1040 } else {
1041 // This is not an 'active heap'. Only do the accounting.
1042 size_t i;
1043 for (i = 0; i < numPtrs; i++) {
1044 assert(ptrs[i] != NULL);
1045 assert(ptr2heap(gHs, ptrs[i]) == heap);
Carl Shapiro8881a802010-08-10 15:55:45 -07001046 countFree(heap, ptrs[i], &numBytes);
Barry Hayesdde8ab02009-05-20 12:10:36 -07001047 }
1048 }
1049 }
Carl Shapiro8881a802010-08-10 15:55:45 -07001050 return numBytes;
Barry Hayesdde8ab02009-05-20 12:10:36 -07001051}
1052
1053/*
Barry Hayes364f9d92010-06-11 16:12:47 -07001054 * Returns true iff <ptr> is in the heap source.
1055 */
1056bool
1057dvmHeapSourceContainsAddress(const void *ptr)
1058{
1059 HS_BOILERPLATE();
1060
1061 return (dvmHeapBitmapCoversAddress(&gHs->liveBits, ptr));
1062}
1063
1064/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001065 * Returns true iff <ptr> was allocated from the heap source.
1066 */
1067bool
1068dvmHeapSourceContains(const void *ptr)
1069{
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001070 HS_BOILERPLATE();
1071
Barry Hayes364f9d92010-06-11 16:12:47 -07001072 if (dvmHeapSourceContainsAddress(ptr)) {
Carl Shapirod77f7fd2010-04-05 19:23:31 -07001073 return dvmHeapBitmapIsObjectBitSet(&gHs->liveBits, ptr) != 0;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001074 }
1075 return false;
1076}
1077
1078/*
1079 * Returns the value of the requested flag.
1080 */
1081bool
1082dvmHeapSourceGetPtrFlag(const void *ptr, enum HeapSourcePtrFlag flag)
1083{
1084 if (ptr == NULL) {
1085 return false;
1086 }
1087
1088 if (flag == HS_CONTAINS) {
1089 return dvmHeapSourceContains(ptr);
1090 } else if (flag == HS_ALLOCATED_IN_ZYGOTE) {
1091 HeapSource *hs = gHs;
1092
1093 HS_BOILERPLATE();
1094
1095 if (hs->sawZygote) {
1096 Heap *heap;
1097
1098 heap = ptr2heap(hs, ptr);
1099 if (heap != NULL) {
1100 /* If the object is not in the active heap, we assume that
1101 * it was allocated as part of zygote.
1102 */
1103 return heap != hs->heaps;
1104 }
1105 }
1106 /* The pointer is outside of any known heap, or we are not
1107 * running in zygote mode.
1108 */
1109 return false;
1110 }
1111
1112 return false;
1113}
1114
1115/*
1116 * Returns the number of usable bytes in an allocated chunk; the size
1117 * may be larger than the size passed to dvmHeapSourceAlloc().
1118 */
1119size_t
1120dvmHeapSourceChunkSize(const void *ptr)
1121{
1122 Heap *heap;
1123
1124 HS_BOILERPLATE();
1125
1126 heap = ptr2heap(gHs, ptr);
1127 if (heap != NULL) {
1128 return mspace_usable_size(heap->msp, ptr);
1129 }
1130 return 0;
1131}
1132
1133/*
1134 * Returns the number of bytes that the heap source has allocated
1135 * from the system using sbrk/mmap, etc.
1136 *
1137 * Caller must hold the heap lock.
1138 */
1139size_t
1140dvmHeapSourceFootprint()
1141{
1142 HS_BOILERPLATE();
1143
1144//TODO: include size of bitmaps?
1145 return oldHeapOverhead(gHs, true);
1146}
1147
1148/*
1149 * Return the real bytes used by old heaps and external memory
1150 * plus the soft usage of the current heap. When a soft limit
1151 * is in effect, this is effectively what it's compared against
1152 * (though, in practice, it only looks at the current heap).
1153 */
1154static size_t
1155getSoftFootprint(bool includeActive)
1156{
1157 HeapSource *hs = gHs;
1158 size_t ret;
1159
1160 HS_BOILERPLATE();
1161
1162 ret = oldHeapOverhead(hs, false) + hs->externalBytesAllocated;
1163 if (includeActive) {
1164 ret += hs->heaps[0].bytesAllocated;
1165 }
1166
1167 return ret;
1168}
1169
1170/*
1171 * Gets the maximum number of bytes that the heap source is allowed
1172 * to allocate from the system.
1173 */
1174size_t
1175dvmHeapSourceGetIdealFootprint()
1176{
1177 HeapSource *hs = gHs;
1178
1179 HS_BOILERPLATE();
1180
1181 return hs->idealSize;
1182}
1183
1184/*
1185 * Sets the soft limit, handling any necessary changes to the allowed
1186 * footprint of the active heap.
1187 */
1188static void
1189setSoftLimit(HeapSource *hs, size_t softLimit)
1190{
1191 /* Compare against the actual footprint, rather than the
1192 * max_allowed, because the heap may not have grown all the
1193 * way to the allowed size yet.
1194 */
Barry Hayes06f254e2009-12-16 16:51:04 -08001195 mspace msp = hs->heaps[0].msp;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001196 size_t currentHeapSize = mspace_footprint(msp);
1197 if (softLimit < currentHeapSize) {
1198 /* Don't let the heap grow any more, and impose a soft limit.
1199 */
1200 mspace_set_max_allowed_footprint(msp, currentHeapSize);
1201 hs->softLimit = softLimit;
1202 } else {
1203 /* Let the heap grow to the requested max, and remove any
1204 * soft limit, if set.
1205 */
1206 mspace_set_max_allowed_footprint(msp, softLimit);
Carl Shapiro2c81bdc2010-09-07 16:19:01 -07001207 hs->softLimit = SIZE_MAX;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001208 }
1209}
1210
1211/*
1212 * Sets the maximum number of bytes that the heap source is allowed
1213 * to allocate from the system. Clamps to the appropriate maximum
1214 * value.
1215 */
1216static void
1217setIdealFootprint(size_t max)
1218{
1219 HeapSource *hs = gHs;
1220#if DEBUG_HEAP_SOURCE
1221 HeapSource oldHs = *hs;
Barry Hayes06f254e2009-12-16 16:51:04 -08001222 mspace msp = hs->heaps[0].msp;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001223 size_t oldAllowedFootprint =
1224 mspace_max_allowed_footprint(msp);
1225#endif
1226
1227 HS_BOILERPLATE();
1228
1229 if (max > hs->absoluteMaxSize) {
1230 LOGI_HEAP("Clamp target GC heap from %zd.%03zdMB to %u.%03uMB\n",
1231 FRACTIONAL_MB(max),
1232 FRACTIONAL_MB(hs->absoluteMaxSize));
1233 max = hs->absoluteMaxSize;
1234 } else if (max < hs->minimumSize) {
1235 max = hs->minimumSize;
1236 }
1237
1238 /* Convert max into a size that applies to the active heap.
1239 * Old heaps and external allocations will count against the ideal size.
1240 */
1241 size_t overhead = getSoftFootprint(false);
1242 size_t activeMax;
1243 if (overhead < max) {
1244 activeMax = max - overhead;
1245 } else {
1246 activeMax = 0;
1247 }
1248
1249 setSoftLimit(hs, activeMax);
1250 hs->idealSize = max;
1251
1252 HSTRACE("IDEAL %zd->%zd (%d), soft %zd->%zd (%d), allowed %zd->%zd (%d), "
1253 "ext %zd\n",
1254 oldHs.idealSize, hs->idealSize, hs->idealSize - oldHs.idealSize,
1255 oldHs.softLimit, hs->softLimit, hs->softLimit - oldHs.softLimit,
1256 oldAllowedFootprint, mspace_max_allowed_footprint(msp),
1257 mspace_max_allowed_footprint(msp) - oldAllowedFootprint,
1258 hs->externalBytesAllocated);
1259
1260}
1261
1262/*
1263 * Make the ideal footprint equal to the current footprint.
1264 */
1265static void
1266snapIdealFootprint()
1267{
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001268 HS_BOILERPLATE();
1269
1270 setIdealFootprint(getSoftFootprint(true));
1271}
1272
1273/*
1274 * Gets the current ideal heap utilization, represented as a number
1275 * between zero and one.
1276 */
1277float dvmGetTargetHeapUtilization()
1278{
1279 HeapSource *hs = gHs;
1280
1281 HS_BOILERPLATE();
1282
1283 return (float)hs->targetUtilization / (float)HEAP_UTILIZATION_MAX;
1284}
1285
1286/*
1287 * Sets the new ideal heap utilization, represented as a number
1288 * between zero and one.
1289 */
1290void dvmSetTargetHeapUtilization(float newTarget)
1291{
1292 HeapSource *hs = gHs;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001293
1294 HS_BOILERPLATE();
1295
1296 /* Clamp it to a reasonable range.
1297 */
1298 // TODO: This may need some tuning.
1299 if (newTarget < 0.2) {
1300 newTarget = 0.2;
1301 } else if (newTarget > 0.8) {
1302 newTarget = 0.8;
1303 }
1304
1305 hs->targetUtilization =
1306 (size_t)(newTarget * (float)HEAP_UTILIZATION_MAX);
Carl Shapirode750892010-06-08 16:37:12 -07001307 LOGV("Set heap target utilization to %zd/%d (%f)\n",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001308 hs->targetUtilization, HEAP_UTILIZATION_MAX, newTarget);
1309}
1310
1311/*
1312 * If set is true, sets the new minimum heap size to size; always
1313 * returns the current (or previous) size. If size is negative,
1314 * removes the current minimum constraint (if present).
1315 */
1316size_t
1317dvmMinimumHeapSize(size_t size, bool set)
1318{
1319 HeapSource *hs = gHs;
1320 size_t oldMinimumSize;
1321
1322 /* gHs caches an entry in gDvm.gcHeap; we need to hold the
1323 * heap lock if we're going to look at it. We also need the
1324 * lock for the call to setIdealFootprint().
1325 */
1326 dvmLockHeap();
1327
1328 HS_BOILERPLATE();
1329
1330 oldMinimumSize = hs->minimumSize;
1331
1332 if (set) {
1333 /* Don't worry about external allocations right now.
1334 * setIdealFootprint() will take them into account when
1335 * minimumSize is used, and it's better to hold onto the
1336 * intended minimumSize than to clamp it arbitrarily based
1337 * on the current allocations.
1338 */
1339 if (size > hs->absoluteMaxSize) {
1340 size = hs->absoluteMaxSize;
1341 }
1342 hs->minimumSize = size;
1343 if (size > hs->idealSize) {
1344 /* Force a snap to the minimum value, which we just set
1345 * and which setIdealFootprint() will take into consideration.
1346 */
1347 setIdealFootprint(hs->idealSize);
1348 }
1349 /* Otherwise we'll just keep it in mind the next time
1350 * setIdealFootprint() is called.
1351 */
1352 }
1353
1354 dvmUnlockHeap();
1355
1356 return oldMinimumSize;
1357}
1358
1359/*
1360 * Given the size of a live set, returns the ideal heap size given
1361 * the current target utilization and MIN/MAX values.
1362 *
1363 * targetUtilization is in the range 1..HEAP_UTILIZATION_MAX.
1364 */
1365static size_t
Carl Shapiro98389d02010-02-14 23:11:47 -08001366getUtilizationTarget(size_t liveSize, size_t targetUtilization)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001367{
1368 size_t targetSize;
1369
1370 /* Use the current target utilization ratio to determine the
1371 * ideal heap size based on the size of the live set.
1372 */
1373 targetSize = (liveSize / targetUtilization) * HEAP_UTILIZATION_MAX;
1374
1375 /* Cap the amount of free space, though, so we don't end up
1376 * with, e.g., 8MB of free space when the live set size hits 8MB.
1377 */
1378 if (targetSize > liveSize + HEAP_IDEAL_FREE) {
1379 targetSize = liveSize + HEAP_IDEAL_FREE;
1380 } else if (targetSize < liveSize + HEAP_MIN_FREE) {
1381 targetSize = liveSize + HEAP_MIN_FREE;
1382 }
1383 return targetSize;
1384}
1385
1386/*
1387 * Given the current contents of the active heap, increase the allowed
1388 * heap footprint to match the target utilization ratio. This
1389 * should only be called immediately after a full mark/sweep.
1390 */
1391void dvmHeapSourceGrowForUtilization()
1392{
1393 HeapSource *hs = gHs;
1394 Heap *heap;
1395 size_t targetHeapSize;
1396 size_t currentHeapUsed;
1397 size_t oldIdealSize;
1398 size_t newHeapMax;
1399 size_t overhead;
Carl Shapiro2c81bdc2010-09-07 16:19:01 -07001400 size_t freeBytes;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001401
1402 HS_BOILERPLATE();
1403 heap = hs2heap(hs);
1404
1405 /* Use the current target utilization ratio to determine the
1406 * ideal heap size based on the size of the live set.
1407 * Note that only the active heap plays any part in this.
1408 *
1409 * Avoid letting the old heaps influence the target free size,
1410 * because they may be full of objects that aren't actually
1411 * in the working set. Just look at the allocated size of
1412 * the current heap.
1413 */
1414 currentHeapUsed = heap->bytesAllocated;
1415#define LET_EXTERNAL_INFLUENCE_UTILIZATION 1
1416#if LET_EXTERNAL_INFLUENCE_UTILIZATION
1417 /* This is a hack to deal with the side-effects of moving
1418 * bitmap data out of the Dalvik heap. Since the amount
1419 * of free space after a GC scales with the size of the
1420 * live set, many apps expected the large free space that
1421 * appeared along with megabytes' worth of bitmaps. When
1422 * the bitmaps were removed, the free size shrank significantly,
1423 * and apps started GCing constantly. This makes it so the
1424 * post-GC free space is the same size it would have been
1425 * if the bitmaps were still in the Dalvik heap.
1426 */
1427 currentHeapUsed += hs->externalBytesAllocated;
1428#endif
1429 targetHeapSize =
Carl Shapiro98389d02010-02-14 23:11:47 -08001430 getUtilizationTarget(currentHeapUsed, hs->targetUtilization);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001431#if LET_EXTERNAL_INFLUENCE_UTILIZATION
1432 currentHeapUsed -= hs->externalBytesAllocated;
1433 targetHeapSize -= hs->externalBytesAllocated;
1434#endif
1435
1436 /* The ideal size includes the old heaps; add overhead so that
1437 * it can be immediately subtracted again in setIdealFootprint().
1438 * If the target heap size would exceed the max, setIdealFootprint()
1439 * will clamp it to a legal value.
1440 */
1441 overhead = getSoftFootprint(false);
1442 oldIdealSize = hs->idealSize;
1443 setIdealFootprint(targetHeapSize + overhead);
1444
Carl Shapiro2c81bdc2010-09-07 16:19:01 -07001445 freeBytes = getAllocLimit(hs);
1446 if (freeBytes < CONCURRENT_MIN_FREE) {
1447 /* Not enough free memory to allow a concurrent GC. */
1448 heap->concurrentStartBytes = SIZE_MAX;
1449 } else {
1450 heap->concurrentStartBytes = freeBytes - CONCURRENT_START;
1451 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001452 newHeapMax = mspace_max_allowed_footprint(heap->msp);
1453 if (softLimited(hs)) {
1454 LOGD_HEAP("GC old usage %zd.%zd%%; now "
1455 "%zd.%03zdMB used / %zd.%03zdMB soft max "
1456 "(%zd.%03zdMB over, "
1457 "%zd.%03zdMB ext, "
1458 "%zd.%03zdMB real max)\n",
1459 FRACTIONAL_PCT(currentHeapUsed, oldIdealSize),
1460 FRACTIONAL_MB(currentHeapUsed),
1461 FRACTIONAL_MB(hs->softLimit),
1462 FRACTIONAL_MB(overhead),
1463 FRACTIONAL_MB(hs->externalBytesAllocated),
1464 FRACTIONAL_MB(newHeapMax));
1465 } else {
1466 LOGD_HEAP("GC old usage %zd.%zd%%; now "
1467 "%zd.%03zdMB used / %zd.%03zdMB real max "
1468 "(%zd.%03zdMB over, "
1469 "%zd.%03zdMB ext)\n",
1470 FRACTIONAL_PCT(currentHeapUsed, oldIdealSize),
1471 FRACTIONAL_MB(currentHeapUsed),
1472 FRACTIONAL_MB(newHeapMax),
1473 FRACTIONAL_MB(overhead),
1474 FRACTIONAL_MB(hs->externalBytesAllocated));
1475 }
1476}
1477
1478/*
1479 * Return free pages to the system.
1480 * TODO: move this somewhere else, especially the native heap part.
1481 */
1482
1483static void releasePagesInRange(void *start, void *end, void *nbytes)
1484{
1485 /* Linux requires that the madvise() start address is page-aligned.
1486 * We also align the end address.
1487 */
1488 start = (void *)ALIGN_UP_TO_PAGE_SIZE(start);
Andy McFadden96516932009-10-28 17:39:02 -07001489 end = (void *)((size_t)end & ~(SYSTEM_PAGE_SIZE - 1));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001490 if (start < end) {
1491 size_t length = (char *)end - (char *)start;
1492 madvise(start, length, MADV_DONTNEED);
1493 *(size_t *)nbytes += length;
1494 }
1495}
1496
1497/*
1498 * Return unused memory to the system if possible.
1499 */
1500void
1501dvmHeapSourceTrim(size_t bytesTrimmed[], size_t arrayLen)
1502{
1503 HeapSource *hs = gHs;
1504 size_t nativeBytes, heapBytes;
1505 size_t i;
1506
1507 HS_BOILERPLATE();
1508
1509 assert(arrayLen >= hs->numHeaps);
1510
1511 heapBytes = 0;
1512 for (i = 0; i < hs->numHeaps; i++) {
1513 Heap *heap = &hs->heaps[i];
1514
1515 /* Return the wilderness chunk to the system.
1516 */
1517 mspace_trim(heap->msp, 0);
1518
1519 /* Return any whole free pages to the system.
1520 */
1521 bytesTrimmed[i] = 0;
Carl Shapirode750892010-06-08 16:37:12 -07001522 mspace_walk_free_pages(heap->msp, releasePagesInRange,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001523 &bytesTrimmed[i]);
1524 heapBytes += bytesTrimmed[i];
1525 }
1526
1527 /* Same for the native heap.
1528 */
1529 dlmalloc_trim(0);
1530 nativeBytes = 0;
1531 dlmalloc_walk_free_pages(releasePagesInRange, &nativeBytes);
1532
1533 LOGD_HEAP("madvised %zd (GC) + %zd (native) = %zd total bytes\n",
1534 heapBytes, nativeBytes, heapBytes + nativeBytes);
1535}
1536
1537/*
1538 * Walks over the heap source and passes every allocated and
1539 * free chunk to the callback.
1540 */
1541void
1542dvmHeapSourceWalk(void(*callback)(const void *chunkptr, size_t chunklen,
1543 const void *userptr, size_t userlen,
1544 void *arg),
1545 void *arg)
1546{
1547 HeapSource *hs = gHs;
1548 size_t i;
1549
1550 HS_BOILERPLATE();
1551
1552 /* Walk the heaps from oldest to newest.
1553 */
1554//TODO: do this in address order
1555 for (i = hs->numHeaps; i > 0; --i) {
1556 mspace_walk_heap(hs->heaps[i-1].msp, callback, arg);
1557 }
1558}
1559
1560/*
1561 * Gets the number of heaps available in the heap source.
1562 *
1563 * Caller must hold the heap lock, because gHs caches a field
1564 * in gDvm.gcHeap.
1565 */
1566size_t
1567dvmHeapSourceGetNumHeaps()
1568{
1569 HeapSource *hs = gHs;
1570
1571 HS_BOILERPLATE();
1572
1573 return hs->numHeaps;
1574}
1575
1576
1577/*
1578 * External allocation tracking
1579 *
1580 * In some situations, memory outside of the heap is tied to the
1581 * lifetime of objects in the heap. Since that memory is kept alive
1582 * by heap objects, it should provide memory pressure that can influence
1583 * GCs.
1584 */
1585
Carl Shapiro1c9d0ab2010-09-24 17:36:53 -07001586/*
1587 * Returns true if the requested number of bytes can be allocated from
1588 * available storage.
1589 */
1590static bool externalBytesAvailable(const HeapSource *hs, size_t numBytes)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001591{
1592 const Heap *heap;
Carl Shapiro1c9d0ab2010-09-24 17:36:53 -07001593 size_t currentHeapSize, newHeapSize;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001594
1595 /* Make sure that this allocation is even possible.
1596 * Don't let the external size plus the actual heap size
1597 * go over the absolute max. This essentially treats
1598 * external allocations as part of the active heap.
1599 *
1600 * Note that this will fail "mysteriously" if there's
1601 * a small softLimit but a large heap footprint.
1602 */
1603 heap = hs2heap(hs);
1604 currentHeapSize = mspace_max_allowed_footprint(heap->msp);
Carl Shapiro1c9d0ab2010-09-24 17:36:53 -07001605 newHeapSize = currentHeapSize + hs->externalBytesAllocated + numBytes;
1606 if (newHeapSize <= heap->absoluteMaxSize) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001607 return true;
1608 }
Carl Shapiro1c9d0ab2010-09-24 17:36:53 -07001609 HSTRACE("externalBytesAvailable(): "
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001610 "footprint %zu + extAlloc %zu + n %zu >= max %zu (space for %zu)\n",
Carl Shapiro1c9d0ab2010-09-24 17:36:53 -07001611 currentHeapSize, hs->externalBytesAllocated, numBytes,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001612 heap->absoluteMaxSize,
1613 heap->absoluteMaxSize -
1614 (currentHeapSize + hs->externalBytesAllocated));
1615 return false;
1616}
1617
1618#define EXTERNAL_TARGET_UTILIZATION 820 // 80%
1619
1620/*
1621 * Tries to update the internal count of externally-allocated memory.
1622 * If there's enough room for that memory, returns true. If not, returns
1623 * false and does not update the count.
Carl Shapirode750892010-06-08 16:37:12 -07001624 *
Carl Shapiro1c9d0ab2010-09-24 17:36:53 -07001625 * The caller must ensure externalBytesAvailable(hs, n) == true.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001626 */
1627static bool
1628externalAlloc(HeapSource *hs, size_t n, bool grow)
1629{
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001630 assert(hs->externalLimit >= hs->externalBytesAllocated);
1631
1632 HSTRACE("externalAlloc(%zd%s)\n", n, grow ? ", grow" : "");
Carl Shapiro1c9d0ab2010-09-24 17:36:53 -07001633 assert(externalBytesAvailable(hs, n)); // The caller must ensure this.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001634
1635 /* External allocations have their own "free space" that they
1636 * can allocate from without causing a GC.
1637 */
1638 if (hs->externalBytesAllocated + n <= hs->externalLimit) {
1639 hs->externalBytesAllocated += n;
Andy McFadden0d615c32010-08-18 12:19:51 -07001640#if PROFILE_EXTERNAL_ALLOCATIONS
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001641 if (gDvm.allocProf.enabled) {
1642 Thread* self = dvmThreadSelf();
1643 gDvm.allocProf.externalAllocCount++;
1644 gDvm.allocProf.externalAllocSize += n;
1645 if (self != NULL) {
1646 self->allocProf.externalAllocCount++;
1647 self->allocProf.externalAllocSize += n;
1648 }
1649 }
1650#endif
1651 return true;
1652 }
1653 if (!grow) {
1654 return false;
1655 }
1656
1657 /* GROW */
1658 hs->externalBytesAllocated += n;
Carl Shapiro98389d02010-02-14 23:11:47 -08001659 hs->externalLimit = getUtilizationTarget(
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001660 hs->externalBytesAllocated, EXTERNAL_TARGET_UTILIZATION);
1661 HSTRACE("EXTERNAL grow limit to %zd\n", hs->externalLimit);
1662 return true;
1663}
1664
1665static void
1666gcForExternalAlloc(bool collectSoftReferences)
1667{
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001668 if (gDvm.allocProf.enabled) {
1669 Thread* self = dvmThreadSelf();
1670 gDvm.allocProf.gcCount++;
1671 if (self != NULL) {
1672 self->allocProf.gcCount++;
1673 }
1674 }
Barry Hayes1b9b4e42010-01-04 10:33:46 -08001675 dvmCollectGarbageInternal(collectSoftReferences, GC_EXTERNAL_ALLOC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001676}
1677
1678/*
Carl Shapiro1c9d0ab2010-09-24 17:36:53 -07001679 * Returns true if there is enough unused storage to perform an
1680 * external allocation of the specified size. If there insufficient
1681 * free storage we try to releasing memory from external allocations
1682 * and trimming the heap.
1683 */
1684static bool externalAllocPossible(const HeapSource *hs, size_t n)
1685{
Carl Shapiro812c1be2010-09-27 14:10:10 -07001686 size_t bytesTrimmed[HEAP_SOURCE_MAX_HEAP_COUNT];
1687
Carl Shapiro1c9d0ab2010-09-24 17:36:53 -07001688 /*
1689 * If there is sufficient space return immediately.
1690 */
1691 if (externalBytesAvailable(hs, n)) {
1692 return true;
1693 }
1694 /*
1695 * There is insufficient space. Wait for the garbage collector to
1696 * become inactive before proceeding.
1697 */
1698 while (gDvm.gcHeap->gcRunning) {
1699 dvmWaitForConcurrentGcToComplete();
1700 }
1701 /*
1702 * The heap may have grown or become trimmed while we were
1703 * waiting.
1704 */
1705 if (externalBytesAvailable(hs, n)) {
1706 return true;
1707 }
1708 /*
Carl Shapiroe8edf082010-09-27 16:55:21 -07001709 * Try a garbage collection that clears soft references. This may
1710 * make trimming more effective.
Carl Shapiro1c9d0ab2010-09-24 17:36:53 -07001711 */
1712 gcForExternalAlloc(true);
1713 if (externalBytesAvailable(hs, n)) {
1714 return true;
1715 }
1716 /*
1717 * Try trimming the mspace to reclaim unused pages.
1718 */
Carl Shapiro812c1be2010-09-27 14:10:10 -07001719 dvmHeapSourceTrim(bytesTrimmed, NELEM(bytesTrimmed));
Carl Shapiro718509c2010-09-28 20:30:42 -07001720 snapIdealFootprint();
Carl Shapiro1c9d0ab2010-09-24 17:36:53 -07001721 if (externalBytesAvailable(hs, n)) {
1722 return true;
1723 }
1724 /*
1725 * Nothing worked, return an error.
1726 */
1727 return false;
1728}
1729
1730/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001731 * Updates the internal count of externally-allocated memory. If there's
1732 * enough room for that memory, returns true. If not, returns false and
1733 * does not update the count.
1734 *
1735 * May cause a GC as a side-effect.
1736 */
1737bool
1738dvmTrackExternalAllocation(size_t n)
1739{
1740 HeapSource *hs = gHs;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001741 bool ret = false;
1742
1743 /* gHs caches an entry in gDvm.gcHeap; we need to hold the
1744 * heap lock if we're going to look at it.
1745 */
1746 dvmLockHeap();
1747
1748 HS_BOILERPLATE();
1749 assert(hs->externalLimit >= hs->externalBytesAllocated);
1750
Carl Shapiro1c9d0ab2010-09-24 17:36:53 -07001751 /*
1752 * The externalAlloc calls require the externalAllocPossible
1753 * invariant to be established.
1754 */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001755 if (!externalAllocPossible(hs, n)) {
1756 LOGE_HEAP("%zd-byte external allocation "
Carl Shapiro1c9d0ab2010-09-24 17:36:53 -07001757 "too large for this process.", n);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001758 goto out;
1759 }
1760
1761 /* Try "allocating" using the existing "free space".
1762 */
1763 HSTRACE("EXTERNAL alloc %zu (%zu < %zu)\n",
1764 n, hs->externalBytesAllocated, hs->externalLimit);
1765 if (externalAlloc(hs, n, false)) {
1766 ret = true;
1767 goto out;
1768 }
Carl Shapiro1c9d0ab2010-09-24 17:36:53 -07001769 /*
1770 * Wait until garbage collector is quiescent before proceeding.
1771 */
1772 while (gDvm.gcHeap->gcRunning) {
Carl Shapiroec47e2e2010-07-01 17:44:46 -07001773 dvmWaitForConcurrentGcToComplete();
Carl Shapiroec47e2e2010-07-01 17:44:46 -07001774 }
Carl Shapiro1c9d0ab2010-09-24 17:36:53 -07001775 /*
1776 * Re-establish the invariant if it was lost while we were
1777 * waiting.
1778 */
1779 if (!externalAllocPossible(hs, n)) {
1780 LOGE_HEAP("%zd-byte external allocation "
1781 "too large for this process.", n);
1782 goto out;
1783 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001784 /* The "allocation" failed. Free up some space by doing
1785 * a full garbage collection. This may grow the heap source
1786 * if the live set is sufficiently large.
1787 */
1788 HSTRACE("EXTERNAL alloc %zd: GC 1\n", n);
1789 gcForExternalAlloc(false); // don't collect SoftReferences
1790 if (externalAlloc(hs, n, false)) {
1791 ret = true;
1792 goto out;
1793 }
1794
1795 /* Even that didn't work; this is an exceptional state.
1796 * Try harder, growing the heap source if necessary.
1797 */
1798 HSTRACE("EXTERNAL alloc %zd: frag\n", n);
1799 ret = externalAlloc(hs, n, true);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001800 if (ret) {
1801 goto out;
1802 }
1803
1804 /* We couldn't even grow enough to satisfy the request.
1805 * Try one last GC, collecting SoftReferences this time.
1806 */
1807 HSTRACE("EXTERNAL alloc %zd: GC 2\n", n);
1808 gcForExternalAlloc(true); // collect SoftReferences
1809 ret = externalAlloc(hs, n, true);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001810 if (!ret) {
1811 LOGE_HEAP("Out of external memory on a %zu-byte allocation.\n", n);
1812 }
1813
Andy McFadden0d615c32010-08-18 12:19:51 -07001814#if PROFILE_EXTERNAL_ALLOCATIONS
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001815 if (gDvm.allocProf.enabled) {
1816 Thread* self = dvmThreadSelf();
1817 gDvm.allocProf.failedExternalAllocCount++;
1818 gDvm.allocProf.failedExternalAllocSize += n;
1819 if (self != NULL) {
1820 self->allocProf.failedExternalAllocCount++;
1821 self->allocProf.failedExternalAllocSize += n;
1822 }
1823 }
1824#endif
1825
1826out:
1827 dvmUnlockHeap();
1828
1829 return ret;
1830}
1831
1832/*
1833 * Reduces the internal count of externally-allocated memory.
1834 */
1835void
1836dvmTrackExternalFree(size_t n)
1837{
1838 HeapSource *hs = gHs;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001839 size_t newExternalLimit;
1840 size_t oldExternalBytesAllocated;
1841
1842 HSTRACE("EXTERNAL free %zu (%zu < %zu)\n",
1843 n, hs->externalBytesAllocated, hs->externalLimit);
1844
1845 /* gHs caches an entry in gDvm.gcHeap; we need to hold the
1846 * heap lock if we're going to look at it.
1847 */
1848 dvmLockHeap();
1849
1850 HS_BOILERPLATE();
1851 assert(hs->externalLimit >= hs->externalBytesAllocated);
1852
1853 oldExternalBytesAllocated = hs->externalBytesAllocated;
1854 if (n <= hs->externalBytesAllocated) {
1855 hs->externalBytesAllocated -= n;
1856 } else {
1857 n = hs->externalBytesAllocated;
1858 hs->externalBytesAllocated = 0;
1859 }
1860
Andy McFadden0d615c32010-08-18 12:19:51 -07001861#if PROFILE_EXTERNAL_ALLOCATIONS
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001862 if (gDvm.allocProf.enabled) {
1863 Thread* self = dvmThreadSelf();
1864 gDvm.allocProf.externalFreeCount++;
1865 gDvm.allocProf.externalFreeSize += n;
1866 if (self != NULL) {
1867 self->allocProf.externalFreeCount++;
1868 self->allocProf.externalFreeSize += n;
1869 }
1870 }
1871#endif
1872
1873 /* Shrink as quickly as we can.
1874 */
Carl Shapiro98389d02010-02-14 23:11:47 -08001875 newExternalLimit = getUtilizationTarget(
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001876 hs->externalBytesAllocated, EXTERNAL_TARGET_UTILIZATION);
1877 if (newExternalLimit < oldExternalBytesAllocated) {
1878 /* Make sure that the remaining free space is at least
1879 * big enough to allocate something of the size that was
1880 * just freed. This makes it more likely that
1881 * externalFree(N); externalAlloc(N);
1882 * will work without causing a GC.
1883 */
1884 HSTRACE("EXTERNAL free preserved %zu extra free bytes\n",
1885 oldExternalBytesAllocated - newExternalLimit);
1886 newExternalLimit = oldExternalBytesAllocated;
1887 }
1888 if (newExternalLimit < hs->externalLimit) {
1889 hs->externalLimit = newExternalLimit;
1890 }
1891
1892 dvmUnlockHeap();
1893}
1894
1895/*
1896 * Returns the number of externally-allocated bytes being tracked by
1897 * dvmTrackExternalAllocation/Free().
1898 */
1899size_t
1900dvmGetExternalBytesAllocated()
1901{
1902 const HeapSource *hs = gHs;
1903 size_t ret;
1904
1905 /* gHs caches an entry in gDvm.gcHeap; we need to hold the
1906 * heap lock if we're going to look at it. We also need the
1907 * lock for the call to setIdealFootprint().
1908 */
1909 dvmLockHeap();
1910 HS_BOILERPLATE();
1911 ret = hs->externalBytesAllocated;
1912 dvmUnlockHeap();
1913
1914 return ret;
1915}
Carl Shapirod25566d2010-03-11 20:39:47 -08001916
1917void *dvmHeapSourceGetImmuneLimit(GcMode mode)
1918{
1919 if (mode == GC_PARTIAL) {
1920 return hs2heap(gHs)->base;
1921 } else {
1922 return NULL;
1923 }
1924}