blob: 792159117e84fd992e07d3559e9c544e9717b898 [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
Carl Shapiroa199eb72010-02-09 16:26:30 -080017#include <cutils/ashmem.h>
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080018#include <cutils/mspace.h>
19#include <limits.h> // for INT_MAX
20#include <sys/mman.h>
21#include <errno.h>
22
23#include "Dalvik.h"
24#include "alloc/Heap.h"
25#include "alloc/HeapInternal.h"
26#include "alloc/HeapSource.h"
27#include "alloc/HeapBitmap.h"
28
29// TODO: find a real header file for these.
30extern int dlmalloc_trim(size_t);
31extern void dlmalloc_walk_free_pages(void(*)(void*, void*, void*), void*);
32
33static void snapIdealFootprint(void);
34static void setIdealFootprint(size_t max);
35
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080036#define ALIGN_UP_TO_PAGE_SIZE(p) \
Andy McFadden96516932009-10-28 17:39:02 -070037 (((size_t)(p) + (SYSTEM_PAGE_SIZE - 1)) & ~(SYSTEM_PAGE_SIZE - 1))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080038#define ALIGN_DOWN_TO_PAGE_SIZE(p) \
Andy McFadden96516932009-10-28 17:39:02 -070039 ((size_t)(p) & ~(SYSTEM_PAGE_SIZE - 1))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080040
41#define HEAP_UTILIZATION_MAX 1024
42#define DEFAULT_HEAP_UTILIZATION 512 // Range 1..HEAP_UTILIZATION_MAX
43#define HEAP_IDEAL_FREE (2 * 1024 * 1024)
44#define HEAP_MIN_FREE (HEAP_IDEAL_FREE / 4)
45
46#define HS_BOILERPLATE() \
47 do { \
48 assert(gDvm.gcHeap != NULL); \
49 assert(gDvm.gcHeap->heapSource != NULL); \
50 assert(gHs == gDvm.gcHeap->heapSource); \
51 } while (0)
52
53#define DEBUG_HEAP_SOURCE 0
54#if DEBUG_HEAP_SOURCE
55#define HSTRACE(...) LOG(LOG_INFO, LOG_TAG "-hs", __VA_ARGS__)
56#else
57#define HSTRACE(...) /**/
58#endif
59
60/*
61=======================================================
62=======================================================
63=======================================================
64
65How will this be used?
66allocating/freeing: Heap.c just wants to say "alloc(n)" and get a ptr
67 - if allocating in large doesn't work, try allocating from small
68Heap.c will use HeapSource.h; HeapSource.c will do the right thing
69 between small and large
70 - some operations should be abstracted; put in a structure
71
72How do we manage the size trade-offs?
73- keep mspace max footprint clamped to actual footprint
74- if small-alloc returns null, adjust large vs. small ratio
75 - give small all available slack and retry
76 - success or fail, snap back to actual footprint and give rest to large
77
78managed as "small actual" + "large actual" + "delta to allowed total footprint"
79- when allocating from one source or the other, give the delta to the
80 active source, but snap back afterwards
81- that may not work so great for a gc heap, because small will always consume.
82 - but we need to use the memory, and the current max is the amount we
83 need to fill before a GC.
84
85Find a way to permanently steal pages from the middle of the heap
86 - segment tricks?
87
88Allocate String and char[] in a separate heap?
89
90Maybe avoid growing small heap, even if there's slack? Look at
91live ratio of small heap after a gc; scale it based on that.
92
93=======================================================
94=======================================================
95=======================================================
96*/
97
98typedef struct {
99 /* The mspace to allocate from.
100 */
Barry Hayes06f254e2009-12-16 16:51:04 -0800101 mspace msp;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800102
103 /* The bitmap that keeps track of where objects are in the heap.
104 */
105 HeapBitmap objectBitmap;
106
107 /* The largest size that this heap is allowed to grow to.
108 */
109 size_t absoluteMaxSize;
110
111 /* Number of bytes allocated from this mspace for objects,
112 * including any overhead. This value is NOT exact, and
113 * should only be used as an input for certain heuristics.
114 */
115 size_t bytesAllocated;
116
117 /* Number of objects currently allocated from this mspace.
118 */
119 size_t objectsAllocated;
120} Heap;
121
122struct HeapSource {
123 /* Target ideal heap utilization ratio; range 1..HEAP_UTILIZATION_MAX
124 */
125 size_t targetUtilization;
126
127 /* Requested minimum heap size, or zero if there is no minimum.
128 */
129 size_t minimumSize;
130
131 /* The starting heap size.
132 */
133 size_t startSize;
134
135 /* The largest that the heap source as a whole is allowed to grow.
136 */
137 size_t absoluteMaxSize;
138
139 /* The desired max size of the heap source as a whole.
140 */
141 size_t idealSize;
142
143 /* The maximum number of bytes allowed to be allocated from the
144 * active heap before a GC is forced. This is used to "shrink" the
145 * heap in lieu of actual compaction.
146 */
147 size_t softLimit;
148
149 /* The heaps; heaps[0] is always the active heap,
150 * which new objects should be allocated from.
151 */
152 Heap heaps[HEAP_SOURCE_MAX_HEAP_COUNT];
153
154 /* The current number of heaps.
155 */
156 size_t numHeaps;
157
158 /* External allocation count.
159 */
160 size_t externalBytesAllocated;
161
162 /* The maximum number of external bytes that may be allocated.
163 */
164 size_t externalLimit;
165
166 /* True if zygote mode was active when the HeapSource was created.
167 */
168 bool sawZygote;
Carl Shapiroa199eb72010-02-09 16:26:30 -0800169
170 /*
171 * The base address of the virtual memory reservation.
172 */
173 char *heapBase;
174
175 /*
176 * The length in bytes of the virtual memory reservation.
177 */
178 size_t heapLength;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800179};
180
181#define hs2heap(hs_) (&((hs_)->heaps[0]))
182
183/*
184 * Returns true iff a soft limit is in effect for the active heap.
185 */
186static inline bool
187softLimited(const HeapSource *hs)
188{
189 /* softLimit will be either INT_MAX or the limit for the
190 * active mspace. idealSize can be greater than softLimit
191 * if there is more than one heap. If there is only one
192 * heap, a non-INT_MAX softLimit should always be the same
193 * as idealSize.
194 */
195 return hs->softLimit <= hs->idealSize;
196}
197
198/*
199 * Returns the current footprint of all heaps. If includeActive
200 * is false, don't count the heap at index 0.
201 */
202static inline size_t
203oldHeapOverhead(const HeapSource *hs, bool includeActive)
204{
205 size_t footprint = 0;
206 size_t i;
207
208 if (includeActive) {
209 i = 0;
210 } else {
211 i = 1;
212 }
213 for (/* i = i */; i < hs->numHeaps; i++) {
214//TODO: include size of bitmaps? If so, don't use bitsLen, listen to .max
215 footprint += mspace_footprint(hs->heaps[i].msp);
216 }
217 return footprint;
218}
219
220/*
221 * Returns the heap that <ptr> could have come from, or NULL
222 * if it could not have come from any heap.
223 */
224static inline Heap *
225ptr2heap(const HeapSource *hs, const void *ptr)
226{
227 const size_t numHeaps = hs->numHeaps;
228 size_t i;
229
230//TODO: unroll this to HEAP_SOURCE_MAX_HEAP_COUNT
231 if (ptr != NULL) {
232 for (i = 0; i < numHeaps; i++) {
233 const Heap *const heap = &hs->heaps[i];
234
235 if (dvmHeapBitmapMayContainObject(&heap->objectBitmap, ptr)) {
236 return (Heap *)heap;
237 }
238 }
239 }
240 return NULL;
241}
242
243/*
244 * Functions to update heapSource->bytesAllocated when an object
245 * is allocated or freed. mspace_usable_size() will give
246 * us a much more accurate picture of heap utilization than
247 * the requested byte sizes would.
248 *
249 * These aren't exact, and should not be treated as such.
250 */
251static inline void
252countAllocation(Heap *heap, const void *ptr, bool isObj)
253{
254 assert(heap->bytesAllocated < mspace_footprint(heap->msp));
255
256 heap->bytesAllocated += mspace_usable_size(heap->msp, ptr) +
257 HEAP_SOURCE_CHUNK_OVERHEAD;
258 if (isObj) {
259 heap->objectsAllocated++;
260 dvmHeapBitmapSetObjectBit(&heap->objectBitmap, ptr);
261 }
262
263 assert(heap->bytesAllocated < mspace_footprint(heap->msp));
264}
265
266static inline void
267countFree(Heap *heap, const void *ptr, bool isObj)
268{
269 size_t delta;
270
271 delta = mspace_usable_size(heap->msp, ptr) + HEAP_SOURCE_CHUNK_OVERHEAD;
272 assert(delta > 0);
273 if (delta < heap->bytesAllocated) {
274 heap->bytesAllocated -= delta;
275 } else {
276 heap->bytesAllocated = 0;
277 }
278 if (isObj) {
279 dvmHeapBitmapClearObjectBit(&heap->objectBitmap, ptr);
280 if (heap->objectsAllocated > 0) {
281 heap->objectsAllocated--;
282 }
283 }
284}
285
286static HeapSource *gHs = NULL;
287
Barry Hayes06f254e2009-12-16 16:51:04 -0800288static mspace
Carl Shapiroa199eb72010-02-09 16:26:30 -0800289createMspace(void *base, size_t startSize, size_t absoluteMaxSize)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800290{
Barry Hayes06f254e2009-12-16 16:51:04 -0800291 mspace msp;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800292
293 /* Create an unlocked dlmalloc mspace to use as
294 * a small-object heap source.
295 *
296 * We start off reserving heapSizeStart/2 bytes but
297 * letting the heap grow to heapSizeStart. This saves
298 * memory in the case where a process uses even less
299 * than the starting size.
300 */
301 LOGV_HEAP("Creating VM heap of size %u\n", startSize);
302 errno = 0;
Carl Shapiroa199eb72010-02-09 16:26:30 -0800303 msp = create_contiguous_mspace_with_base(startSize/2,
304 absoluteMaxSize, /*locked=*/false, base);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800305 if (msp != NULL) {
306 /* Don't let the heap grow past the starting size without
307 * our intervention.
308 */
309 mspace_set_max_allowed_footprint(msp, startSize);
310 } else {
311 /* There's no guarantee that errno has meaning when the call
312 * fails, but it often does.
313 */
314 LOGE_HEAP("Can't create VM heap of size (%u,%u) (errno=%d)\n",
315 startSize/2, absoluteMaxSize, errno);
316 }
317
318 return msp;
319}
320
321static bool
Barry Hayes06f254e2009-12-16 16:51:04 -0800322addNewHeap(HeapSource *hs, mspace msp, size_t mspAbsoluteMaxSize)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800323{
324 Heap heap;
Carl Shapiroa199eb72010-02-09 16:26:30 -0800325 void *base;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800326
327 if (hs->numHeaps >= HEAP_SOURCE_MAX_HEAP_COUNT) {
328 LOGE("Attempt to create too many heaps (%zd >= %zd)\n",
329 hs->numHeaps, HEAP_SOURCE_MAX_HEAP_COUNT);
330 dvmAbort();
331 return false;
332 }
333
334 memset(&heap, 0, sizeof(heap));
335
336 if (msp != NULL) {
337 heap.msp = msp;
338 heap.absoluteMaxSize = mspAbsoluteMaxSize;
339 } else {
Carl Shapiro8d724802010-02-14 18:40:47 -0800340 size_t diff, overhead;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800341
342 overhead = oldHeapOverhead(hs, true);
343 if (overhead + HEAP_MIN_FREE >= hs->absoluteMaxSize) {
344 LOGE_HEAP("No room to create any more heaps "
345 "(%zd overhead, %zd max)\n",
346 overhead, hs->absoluteMaxSize);
347 return false;
348 }
349 heap.absoluteMaxSize = hs->absoluteMaxSize - overhead;
Carl Shapiro8d724802010-02-14 18:40:47 -0800350 base = contiguous_mspace_sbrk0(hs->heaps[0].msp);
351 base = (void *)ALIGN_UP_TO_PAGE_SIZE(base);
Carl Shapiroa199eb72010-02-09 16:26:30 -0800352 heap.msp = createMspace(base, HEAP_MIN_FREE, heap.absoluteMaxSize);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800353 if (heap.msp == NULL) {
354 return false;
355 }
Carl Shapiro8d724802010-02-14 18:40:47 -0800356 diff = (size_t)base - hs->heaps[0].objectBitmap.base;
357 hs->heaps[0].objectBitmap.bitsLen = HB_OFFSET_TO_INDEX(diff) * 4;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800358 }
359 if (!dvmHeapBitmapInit(&heap.objectBitmap,
360 (void *)ALIGN_DOWN_TO_PAGE_SIZE(heap.msp),
361 heap.absoluteMaxSize,
362 "objects"))
363 {
364 LOGE_HEAP("Can't create objectBitmap\n");
Carl Shapiroa199eb72010-02-09 16:26:30 -0800365 return false;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800366 }
367
368 /* Don't let the soon-to-be-old heap grow any further.
369 */
370 if (hs->numHeaps > 0) {
Barry Hayes06f254e2009-12-16 16:51:04 -0800371 mspace msp = hs->heaps[0].msp;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800372 mspace_set_max_allowed_footprint(msp, mspace_footprint(msp));
373 }
374
375 /* Put the new heap in the list, at heaps[0].
376 * Shift existing heaps down.
377 */
378 memmove(&hs->heaps[1], &hs->heaps[0], hs->numHeaps * sizeof(hs->heaps[0]));
379 hs->heaps[0] = heap;
380 hs->numHeaps++;
381
382 return true;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800383}
384
385/*
386 * Initializes the heap source; must be called before any other
387 * dvmHeapSource*() functions. Returns a GcHeap structure
388 * allocated from the heap source.
389 */
390GcHeap *
391dvmHeapSourceStartup(size_t startSize, size_t absoluteMaxSize)
392{
393 GcHeap *gcHeap;
394 HeapSource *hs;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800395 mspace msp;
Carl Shapiroa199eb72010-02-09 16:26:30 -0800396 size_t length;
397 void *base;
398 int fd, ret;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800399
400 assert(gHs == NULL);
401
402 if (startSize > absoluteMaxSize) {
403 LOGE("Bad heap parameters (start=%d, max=%d)\n",
404 startSize, absoluteMaxSize);
405 return NULL;
406 }
407
Carl Shapiroa199eb72010-02-09 16:26:30 -0800408 /*
409 * Allocate a contiguous region of virtual memory to subdivided
410 * among the heaps managed by the garbage collector.
411 */
412 length = ALIGN_UP_TO_PAGE_SIZE(absoluteMaxSize);
413 length *= HEAP_SOURCE_MAX_HEAP_COUNT;
414 fd = ashmem_create_region("the-java-heap", length);
415 if (fd == -1) {
416 return NULL;
417 }
418 base = mmap(NULL, length, PROT_NONE, MAP_PRIVATE, fd, 0);
419 if (base == MAP_FAILED) {
420 return NULL;
421 }
422 ret = close(fd);
423 if (ret == -1) {
424 goto fail;
425 }
426
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800427 /* Create an unlocked dlmalloc mspace to use as
428 * the small object heap source.
429 */
Carl Shapiroa199eb72010-02-09 16:26:30 -0800430 msp = createMspace(base, startSize, absoluteMaxSize);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800431 if (msp == NULL) {
Carl Shapiroa199eb72010-02-09 16:26:30 -0800432 goto fail;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800433 }
434
435 /* Allocate a descriptor from the heap we just created.
436 */
437 gcHeap = mspace_malloc(msp, sizeof(*gcHeap));
438 if (gcHeap == NULL) {
439 LOGE_HEAP("Can't allocate heap descriptor\n");
440 goto fail;
441 }
442 memset(gcHeap, 0, sizeof(*gcHeap));
443
444 hs = mspace_malloc(msp, sizeof(*hs));
445 if (hs == NULL) {
446 LOGE_HEAP("Can't allocate heap source\n");
447 goto fail;
448 }
449 memset(hs, 0, sizeof(*hs));
450
451 hs->targetUtilization = DEFAULT_HEAP_UTILIZATION;
452 hs->minimumSize = 0;
453 hs->startSize = startSize;
454 hs->absoluteMaxSize = absoluteMaxSize;
455 hs->idealSize = startSize;
456 hs->softLimit = INT_MAX; // no soft limit at first
457 hs->numHeaps = 0;
458 hs->sawZygote = gDvm.zygote;
Carl Shapiroa199eb72010-02-09 16:26:30 -0800459 hs->heapBase = base;
460 hs->heapLength = length;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800461 if (!addNewHeap(hs, msp, absoluteMaxSize)) {
462 LOGE_HEAP("Can't add initial heap\n");
463 goto fail;
464 }
465
466 gcHeap->heapSource = hs;
467
468 countAllocation(hs2heap(hs), gcHeap, false);
469 countAllocation(hs2heap(hs), hs, false);
470
471 gHs = hs;
472 return gcHeap;
473
474fail:
Carl Shapiroa199eb72010-02-09 16:26:30 -0800475 munmap(base, length);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800476 return NULL;
477}
478
479/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800480 * This is called while in zygote mode, right before we fork() for the
481 * first time. We create a heap for all future zygote process allocations,
482 * in an attempt to avoid touching pages in the zygote heap. (This would
483 * probably be unnecessary if we had a compacting GC -- the source of our
484 * troubles is small allocations filling in the gaps from larger ones.)
485 */
486bool
487dvmHeapSourceStartupBeforeFork()
488{
489 HeapSource *hs = gHs; // use a local to avoid the implicit "volatile"
490
491 HS_BOILERPLATE();
492
493 assert(gDvm.zygote);
494
495 if (!gDvm.newZygoteHeapAllocated) {
496 /* Create a new heap for post-fork zygote allocations. We only
497 * try once, even if it fails.
498 */
Andy McFaddendced7942009-11-17 13:13:34 -0800499 LOGV("Splitting out new zygote heap\n");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800500 gDvm.newZygoteHeapAllocated = true;
501 return addNewHeap(hs, NULL, 0);
502 }
503 return true;
504}
505
506/*
Carl Shapiroa199eb72010-02-09 16:26:30 -0800507 * Tears down the entire GcHeap structure and all of the substructures
508 * attached to it. This call has the side effect of setting the given
509 * gcHeap pointer and gHs to NULL.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800510 */
511void
Carl Shapiroa199eb72010-02-09 16:26:30 -0800512dvmHeapSourceShutdown(GcHeap **gcHeap)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800513{
Carl Shapiroa199eb72010-02-09 16:26:30 -0800514 if (*gcHeap != NULL && (*gcHeap)->heapSource != NULL) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800515 HeapSource *hs;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800516 size_t i;
517
Carl Shapiroa199eb72010-02-09 16:26:30 -0800518 hs = (*gcHeap)->heapSource;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800519
Carl Shapiroa199eb72010-02-09 16:26:30 -0800520 assert((char *)*gcHeap >= hs->heapBase);
521 assert((char *)*gcHeap < hs->heapBase + hs->heapLength);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800522
Carl Shapiroa199eb72010-02-09 16:26:30 -0800523 for (i = 0; i < hs->numHeaps; i++) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800524 Heap *heap = &hs->heaps[i];
525
526 dvmHeapBitmapDelete(&heap->objectBitmap);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800527 }
Carl Shapiroa199eb72010-02-09 16:26:30 -0800528
529 munmap(hs->heapBase, hs->heapLength);
530 gHs = NULL;
531 *gcHeap = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800532 }
533}
534
535/*
536 * Returns the requested value. If the per-heap stats are requested, fill
537 * them as well.
538 *
539 * Caller must hold the heap lock.
540 */
541size_t
542dvmHeapSourceGetValue(enum HeapSourceValueSpec spec, size_t perHeapStats[],
543 size_t arrayLen)
544{
545 HeapSource *hs = gHs;
546 size_t value = 0;
547 size_t total = 0;
548 size_t i;
549
550 HS_BOILERPLATE();
551
552 switch (spec) {
553 case HS_EXTERNAL_BYTES_ALLOCATED:
554 return hs->externalBytesAllocated;
555 case HS_EXTERNAL_LIMIT:
556 return hs->externalLimit;
557 default:
558 // look at all heaps.
559 ;
560 }
561
562 assert(arrayLen >= hs->numHeaps || perHeapStats == NULL);
563 for (i = 0; i < hs->numHeaps; i++) {
564 Heap *const heap = &hs->heaps[i];
565
566 switch (spec) {
567 case HS_FOOTPRINT:
568 value = mspace_footprint(heap->msp);
569 break;
570 case HS_ALLOWED_FOOTPRINT:
571 value = mspace_max_allowed_footprint(heap->msp);
572 break;
573 case HS_BYTES_ALLOCATED:
574 value = heap->bytesAllocated;
575 break;
576 case HS_OBJECTS_ALLOCATED:
577 value = heap->objectsAllocated;
578 break;
579 default:
580 // quiet gcc
581 break;
582 }
583 if (perHeapStats) {
584 perHeapStats[i] = value;
585 }
586 total += value;
587 }
588 return total;
589}
590
591/*
592 * Writes shallow copies of the currently-used bitmaps into outBitmaps,
593 * returning the number of bitmaps written. Returns <0 if the array
594 * was not long enough.
595 */
596ssize_t
597dvmHeapSourceGetObjectBitmaps(HeapBitmap outBitmaps[], size_t maxBitmaps)
598{
599 HeapSource *hs = gHs;
600
601 HS_BOILERPLATE();
602
603 if (maxBitmaps >= hs->numHeaps) {
604 size_t i;
605
606 for (i = 0; i < hs->numHeaps; i++) {
607 outBitmaps[i] = hs->heaps[i].objectBitmap;
608 }
609 return i;
610 }
611 return -1;
612}
613
614/*
615 * Replaces the object location HeapBitmaps with the elements of
616 * <objectBitmaps>. The elements of <objectBitmaps> are overwritten
617 * with shallow copies of the old bitmaps.
618 *
619 * Returns false if the number of bitmaps doesn't match the number
620 * of heaps.
621 */
622bool
623dvmHeapSourceReplaceObjectBitmaps(HeapBitmap objectBitmaps[], size_t nBitmaps)
624{
625 HeapSource *hs = gHs;
626 size_t i;
627
628 HS_BOILERPLATE();
629
630 if (nBitmaps != hs->numHeaps) {
631 return false;
632 }
633
634 for (i = 0; i < hs->numHeaps; i++) {
635 Heap *heap = &hs->heaps[i];
636 HeapBitmap swap;
637
638 swap = heap->objectBitmap;
639 heap->objectBitmap = objectBitmaps[i];
640 objectBitmaps[i] = swap;
641 }
642 return true;
643}
644
645/*
646 * Allocates <n> bytes of zeroed data.
647 */
648void *
649dvmHeapSourceAlloc(size_t n)
650{
651 HeapSource *hs = gHs;
652 Heap *heap;
653 void *ptr;
654
655 HS_BOILERPLATE();
656 heap = hs2heap(hs);
657
658 if (heap->bytesAllocated + n <= hs->softLimit) {
659// TODO: allocate large blocks (>64k?) as separate mmap regions so that
660// they don't increase the high-water mark when they're freed.
661// TODO: zero out large objects using madvise
662 ptr = mspace_calloc(heap->msp, 1, n);
663 if (ptr != NULL) {
664 countAllocation(heap, ptr, true);
665 }
666 } else {
667 /* This allocation would push us over the soft limit;
668 * act as if the heap is full.
669 */
670 LOGV_HEAP("softLimit of %zd.%03zdMB hit for %zd-byte allocation\n",
671 FRACTIONAL_MB(hs->softLimit), n);
672 ptr = NULL;
673 }
674 return ptr;
675}
676
677/* Remove any hard limits, try to allocate, and shrink back down.
678 * Last resort when trying to allocate an object.
679 */
680static void *
681heapAllocAndGrow(HeapSource *hs, Heap *heap, size_t n)
682{
683 void *ptr;
684 size_t max;
685
686 /* Grow as much as possible, but don't let the real footprint
687 * plus external allocations go over the absolute max.
688 */
689 max = heap->absoluteMaxSize;
690 if (max > hs->externalBytesAllocated) {
691 max -= hs->externalBytesAllocated;
692
693 mspace_set_max_allowed_footprint(heap->msp, max);
694 ptr = dvmHeapSourceAlloc(n);
695
696 /* Shrink back down as small as possible. Our caller may
697 * readjust max_allowed to a more appropriate value.
698 */
699 mspace_set_max_allowed_footprint(heap->msp,
700 mspace_footprint(heap->msp));
701 } else {
702 ptr = NULL;
703 }
704
705 return ptr;
706}
707
708/*
709 * Allocates <n> bytes of zeroed data, growing as much as possible
710 * if necessary.
711 */
712void *
713dvmHeapSourceAllocAndGrow(size_t n)
714{
715 HeapSource *hs = gHs;
716 Heap *heap;
717 void *ptr;
718 size_t oldIdealSize;
719
720 HS_BOILERPLATE();
721 heap = hs2heap(hs);
722
723 ptr = dvmHeapSourceAlloc(n);
724 if (ptr != NULL) {
725 return ptr;
726 }
727
728 oldIdealSize = hs->idealSize;
729 if (softLimited(hs)) {
730 /* We're soft-limited. Try removing the soft limit to
731 * see if we can allocate without actually growing.
732 */
733 hs->softLimit = INT_MAX;
734 ptr = dvmHeapSourceAlloc(n);
735 if (ptr != NULL) {
736 /* Removing the soft limit worked; fix things up to
737 * reflect the new effective ideal size.
738 */
739 snapIdealFootprint();
740 return ptr;
741 }
742 // softLimit intentionally left at INT_MAX.
743 }
744
745 /* We're not soft-limited. Grow the heap to satisfy the request.
746 * If this call fails, no footprints will have changed.
747 */
748 ptr = heapAllocAndGrow(hs, heap, n);
749 if (ptr != NULL) {
750 /* The allocation succeeded. Fix up the ideal size to
751 * reflect any footprint modifications that had to happen.
752 */
753 snapIdealFootprint();
754 } else {
755 /* We just couldn't do it. Restore the original ideal size,
756 * fixing up softLimit if necessary.
757 */
758 setIdealFootprint(oldIdealSize);
759 }
760 return ptr;
761}
762
763/*
764 * Frees the memory pointed to by <ptr>, which may be NULL.
765 */
766void
767dvmHeapSourceFree(void *ptr)
768{
769 Heap *heap;
770
771 HS_BOILERPLATE();
772
773 heap = ptr2heap(gHs, ptr);
774 if (heap != NULL) {
775 countFree(heap, ptr, true);
776 /* Only free objects that are in the active heap.
777 * Touching old heaps would pull pages into this process.
778 */
779 if (heap == gHs->heaps) {
780 mspace_free(heap->msp, ptr);
781 }
782 }
783}
784
785/*
Barry Hayesdde8ab02009-05-20 12:10:36 -0700786 * Frees the first numPtrs objects in the ptrs list. The list must
787 * contain addresses all in the same mspace, and must be in increasing
788 * order. This implies that there are no duplicates, and no entries
789 * are NULL.
790 */
791void
792dvmHeapSourceFreeList(size_t numPtrs, void **ptrs)
793{
794 Heap *heap;
795
796 HS_BOILERPLATE();
797
798 if (numPtrs == 0) {
799 return;
800 }
801
802 assert(ptrs != NULL);
803 assert(*ptrs != NULL);
804 heap = ptr2heap(gHs, *ptrs);
805 if (heap != NULL) {
806 mspace *msp = heap->msp;
807 // Calling mspace_free on shared heaps disrupts sharing too
808 // much. For heap[0] -- the 'active heap' -- we call
809 // mspace_free, but on the other heaps we only do some
810 // accounting.
811 if (heap == gHs->heaps) {
812 // mspace_merge_objects takes two allocated objects, and
813 // if the second immediately follows the first, will merge
814 // them, returning a larger object occupying the same
815 // memory. This is a local operation, and doesn't require
816 // dlmalloc to manipulate any freelists. It's pretty
817 // inexpensive compared to free().
818
819 // ptrs is an array of objects all in memory order, and if
820 // client code has been allocating lots of short-lived
821 // objects, this is likely to contain runs of objects all
822 // now garbage, and thus highly amenable to this optimization.
823
824 // Unroll the 0th iteration around the loop below,
825 // countFree ptrs[0] and initializing merged.
826 assert(ptrs[0] != NULL);
827 assert(ptr2heap(gHs, ptrs[0]) == heap);
828 countFree(heap, ptrs[0], true);
829 void *merged = ptrs[0];
830
831 size_t i;
832 for (i = 1; i < numPtrs; i++) {
833 assert(merged != NULL);
834 assert(ptrs[i] != NULL);
835 assert((intptr_t)merged < (intptr_t)ptrs[i]);
836 assert(ptr2heap(gHs, ptrs[i]) == heap);
837 countFree(heap, ptrs[i], true);
838 // Try to merge. If it works, merged now includes the
839 // memory of ptrs[i]. If it doesn't, free merged, and
840 // see if ptrs[i] starts a new run of adjacent
841 // objects to merge.
842 if (mspace_merge_objects(msp, merged, ptrs[i]) == NULL) {
843 mspace_free(msp, merged);
844 merged = ptrs[i];
845 }
846 }
847 assert(merged != NULL);
848 mspace_free(msp, merged);
849 } else {
850 // This is not an 'active heap'. Only do the accounting.
851 size_t i;
852 for (i = 0; i < numPtrs; i++) {
853 assert(ptrs[i] != NULL);
854 assert(ptr2heap(gHs, ptrs[i]) == heap);
855 countFree(heap, ptrs[i], true);
856 }
857 }
858 }
859}
860
861/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800862 * Returns true iff <ptr> was allocated from the heap source.
863 */
864bool
865dvmHeapSourceContains(const void *ptr)
866{
867 Heap *heap;
868
869 HS_BOILERPLATE();
870
871 heap = ptr2heap(gHs, ptr);
872 if (heap != NULL) {
873 return dvmHeapBitmapIsObjectBitSet(&heap->objectBitmap, ptr) != 0;
874 }
875 return false;
876}
877
878/*
879 * Returns the value of the requested flag.
880 */
881bool
882dvmHeapSourceGetPtrFlag(const void *ptr, enum HeapSourcePtrFlag flag)
883{
884 if (ptr == NULL) {
885 return false;
886 }
887
888 if (flag == HS_CONTAINS) {
889 return dvmHeapSourceContains(ptr);
890 } else if (flag == HS_ALLOCATED_IN_ZYGOTE) {
891 HeapSource *hs = gHs;
892
893 HS_BOILERPLATE();
894
895 if (hs->sawZygote) {
896 Heap *heap;
897
898 heap = ptr2heap(hs, ptr);
899 if (heap != NULL) {
900 /* If the object is not in the active heap, we assume that
901 * it was allocated as part of zygote.
902 */
903 return heap != hs->heaps;
904 }
905 }
906 /* The pointer is outside of any known heap, or we are not
907 * running in zygote mode.
908 */
909 return false;
910 }
911
912 return false;
913}
914
915/*
916 * Returns the number of usable bytes in an allocated chunk; the size
917 * may be larger than the size passed to dvmHeapSourceAlloc().
918 */
919size_t
920dvmHeapSourceChunkSize(const void *ptr)
921{
922 Heap *heap;
923
924 HS_BOILERPLATE();
925
926 heap = ptr2heap(gHs, ptr);
927 if (heap != NULL) {
928 return mspace_usable_size(heap->msp, ptr);
929 }
930 return 0;
931}
932
933/*
934 * Returns the number of bytes that the heap source has allocated
935 * from the system using sbrk/mmap, etc.
936 *
937 * Caller must hold the heap lock.
938 */
939size_t
940dvmHeapSourceFootprint()
941{
942 HS_BOILERPLATE();
943
944//TODO: include size of bitmaps?
945 return oldHeapOverhead(gHs, true);
946}
947
948/*
949 * Return the real bytes used by old heaps and external memory
950 * plus the soft usage of the current heap. When a soft limit
951 * is in effect, this is effectively what it's compared against
952 * (though, in practice, it only looks at the current heap).
953 */
954static size_t
955getSoftFootprint(bool includeActive)
956{
957 HeapSource *hs = gHs;
958 size_t ret;
959
960 HS_BOILERPLATE();
961
962 ret = oldHeapOverhead(hs, false) + hs->externalBytesAllocated;
963 if (includeActive) {
964 ret += hs->heaps[0].bytesAllocated;
965 }
966
967 return ret;
968}
969
970/*
971 * Gets the maximum number of bytes that the heap source is allowed
972 * to allocate from the system.
973 */
974size_t
975dvmHeapSourceGetIdealFootprint()
976{
977 HeapSource *hs = gHs;
978
979 HS_BOILERPLATE();
980
981 return hs->idealSize;
982}
983
984/*
985 * Sets the soft limit, handling any necessary changes to the allowed
986 * footprint of the active heap.
987 */
988static void
989setSoftLimit(HeapSource *hs, size_t softLimit)
990{
991 /* Compare against the actual footprint, rather than the
992 * max_allowed, because the heap may not have grown all the
993 * way to the allowed size yet.
994 */
Barry Hayes06f254e2009-12-16 16:51:04 -0800995 mspace msp = hs->heaps[0].msp;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800996 size_t currentHeapSize = mspace_footprint(msp);
997 if (softLimit < currentHeapSize) {
998 /* Don't let the heap grow any more, and impose a soft limit.
999 */
1000 mspace_set_max_allowed_footprint(msp, currentHeapSize);
1001 hs->softLimit = softLimit;
1002 } else {
1003 /* Let the heap grow to the requested max, and remove any
1004 * soft limit, if set.
1005 */
1006 mspace_set_max_allowed_footprint(msp, softLimit);
1007 hs->softLimit = INT_MAX;
1008 }
1009}
1010
1011/*
1012 * Sets the maximum number of bytes that the heap source is allowed
1013 * to allocate from the system. Clamps to the appropriate maximum
1014 * value.
1015 */
1016static void
1017setIdealFootprint(size_t max)
1018{
1019 HeapSource *hs = gHs;
1020#if DEBUG_HEAP_SOURCE
1021 HeapSource oldHs = *hs;
Barry Hayes06f254e2009-12-16 16:51:04 -08001022 mspace msp = hs->heaps[0].msp;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001023 size_t oldAllowedFootprint =
1024 mspace_max_allowed_footprint(msp);
1025#endif
1026
1027 HS_BOILERPLATE();
1028
1029 if (max > hs->absoluteMaxSize) {
1030 LOGI_HEAP("Clamp target GC heap from %zd.%03zdMB to %u.%03uMB\n",
1031 FRACTIONAL_MB(max),
1032 FRACTIONAL_MB(hs->absoluteMaxSize));
1033 max = hs->absoluteMaxSize;
1034 } else if (max < hs->minimumSize) {
1035 max = hs->minimumSize;
1036 }
1037
1038 /* Convert max into a size that applies to the active heap.
1039 * Old heaps and external allocations will count against the ideal size.
1040 */
1041 size_t overhead = getSoftFootprint(false);
1042 size_t activeMax;
1043 if (overhead < max) {
1044 activeMax = max - overhead;
1045 } else {
1046 activeMax = 0;
1047 }
1048
1049 setSoftLimit(hs, activeMax);
1050 hs->idealSize = max;
1051
1052 HSTRACE("IDEAL %zd->%zd (%d), soft %zd->%zd (%d), allowed %zd->%zd (%d), "
1053 "ext %zd\n",
1054 oldHs.idealSize, hs->idealSize, hs->idealSize - oldHs.idealSize,
1055 oldHs.softLimit, hs->softLimit, hs->softLimit - oldHs.softLimit,
1056 oldAllowedFootprint, mspace_max_allowed_footprint(msp),
1057 mspace_max_allowed_footprint(msp) - oldAllowedFootprint,
1058 hs->externalBytesAllocated);
1059
1060}
1061
1062/*
1063 * Make the ideal footprint equal to the current footprint.
1064 */
1065static void
1066snapIdealFootprint()
1067{
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001068 HS_BOILERPLATE();
1069
1070 setIdealFootprint(getSoftFootprint(true));
1071}
1072
1073/*
1074 * Gets the current ideal heap utilization, represented as a number
1075 * between zero and one.
1076 */
1077float dvmGetTargetHeapUtilization()
1078{
1079 HeapSource *hs = gHs;
1080
1081 HS_BOILERPLATE();
1082
1083 return (float)hs->targetUtilization / (float)HEAP_UTILIZATION_MAX;
1084}
1085
1086/*
1087 * Sets the new ideal heap utilization, represented as a number
1088 * between zero and one.
1089 */
1090void dvmSetTargetHeapUtilization(float newTarget)
1091{
1092 HeapSource *hs = gHs;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001093
1094 HS_BOILERPLATE();
1095
1096 /* Clamp it to a reasonable range.
1097 */
1098 // TODO: This may need some tuning.
1099 if (newTarget < 0.2) {
1100 newTarget = 0.2;
1101 } else if (newTarget > 0.8) {
1102 newTarget = 0.8;
1103 }
1104
1105 hs->targetUtilization =
1106 (size_t)(newTarget * (float)HEAP_UTILIZATION_MAX);
1107 LOGV("Set heap target utilization to %zd/%d (%f)\n",
1108 hs->targetUtilization, HEAP_UTILIZATION_MAX, newTarget);
1109}
1110
1111/*
1112 * If set is true, sets the new minimum heap size to size; always
1113 * returns the current (or previous) size. If size is negative,
1114 * removes the current minimum constraint (if present).
1115 */
1116size_t
1117dvmMinimumHeapSize(size_t size, bool set)
1118{
1119 HeapSource *hs = gHs;
1120 size_t oldMinimumSize;
1121
1122 /* gHs caches an entry in gDvm.gcHeap; we need to hold the
1123 * heap lock if we're going to look at it. We also need the
1124 * lock for the call to setIdealFootprint().
1125 */
1126 dvmLockHeap();
1127
1128 HS_BOILERPLATE();
1129
1130 oldMinimumSize = hs->minimumSize;
1131
1132 if (set) {
1133 /* Don't worry about external allocations right now.
1134 * setIdealFootprint() will take them into account when
1135 * minimumSize is used, and it's better to hold onto the
1136 * intended minimumSize than to clamp it arbitrarily based
1137 * on the current allocations.
1138 */
1139 if (size > hs->absoluteMaxSize) {
1140 size = hs->absoluteMaxSize;
1141 }
1142 hs->minimumSize = size;
1143 if (size > hs->idealSize) {
1144 /* Force a snap to the minimum value, which we just set
1145 * and which setIdealFootprint() will take into consideration.
1146 */
1147 setIdealFootprint(hs->idealSize);
1148 }
1149 /* Otherwise we'll just keep it in mind the next time
1150 * setIdealFootprint() is called.
1151 */
1152 }
1153
1154 dvmUnlockHeap();
1155
1156 return oldMinimumSize;
1157}
1158
1159/*
1160 * Given the size of a live set, returns the ideal heap size given
1161 * the current target utilization and MIN/MAX values.
1162 *
1163 * targetUtilization is in the range 1..HEAP_UTILIZATION_MAX.
1164 */
1165static size_t
Carl Shapiro98389d02010-02-14 23:11:47 -08001166getUtilizationTarget(size_t liveSize, size_t targetUtilization)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001167{
1168 size_t targetSize;
1169
1170 /* Use the current target utilization ratio to determine the
1171 * ideal heap size based on the size of the live set.
1172 */
1173 targetSize = (liveSize / targetUtilization) * HEAP_UTILIZATION_MAX;
1174
1175 /* Cap the amount of free space, though, so we don't end up
1176 * with, e.g., 8MB of free space when the live set size hits 8MB.
1177 */
1178 if (targetSize > liveSize + HEAP_IDEAL_FREE) {
1179 targetSize = liveSize + HEAP_IDEAL_FREE;
1180 } else if (targetSize < liveSize + HEAP_MIN_FREE) {
1181 targetSize = liveSize + HEAP_MIN_FREE;
1182 }
1183 return targetSize;
1184}
1185
1186/*
1187 * Given the current contents of the active heap, increase the allowed
1188 * heap footprint to match the target utilization ratio. This
1189 * should only be called immediately after a full mark/sweep.
1190 */
1191void dvmHeapSourceGrowForUtilization()
1192{
1193 HeapSource *hs = gHs;
1194 Heap *heap;
1195 size_t targetHeapSize;
1196 size_t currentHeapUsed;
1197 size_t oldIdealSize;
1198 size_t newHeapMax;
1199 size_t overhead;
1200
1201 HS_BOILERPLATE();
1202 heap = hs2heap(hs);
1203
1204 /* Use the current target utilization ratio to determine the
1205 * ideal heap size based on the size of the live set.
1206 * Note that only the active heap plays any part in this.
1207 *
1208 * Avoid letting the old heaps influence the target free size,
1209 * because they may be full of objects that aren't actually
1210 * in the working set. Just look at the allocated size of
1211 * the current heap.
1212 */
1213 currentHeapUsed = heap->bytesAllocated;
1214#define LET_EXTERNAL_INFLUENCE_UTILIZATION 1
1215#if LET_EXTERNAL_INFLUENCE_UTILIZATION
1216 /* This is a hack to deal with the side-effects of moving
1217 * bitmap data out of the Dalvik heap. Since the amount
1218 * of free space after a GC scales with the size of the
1219 * live set, many apps expected the large free space that
1220 * appeared along with megabytes' worth of bitmaps. When
1221 * the bitmaps were removed, the free size shrank significantly,
1222 * and apps started GCing constantly. This makes it so the
1223 * post-GC free space is the same size it would have been
1224 * if the bitmaps were still in the Dalvik heap.
1225 */
1226 currentHeapUsed += hs->externalBytesAllocated;
1227#endif
1228 targetHeapSize =
Carl Shapiro98389d02010-02-14 23:11:47 -08001229 getUtilizationTarget(currentHeapUsed, hs->targetUtilization);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001230#if LET_EXTERNAL_INFLUENCE_UTILIZATION
1231 currentHeapUsed -= hs->externalBytesAllocated;
1232 targetHeapSize -= hs->externalBytesAllocated;
1233#endif
1234
1235 /* The ideal size includes the old heaps; add overhead so that
1236 * it can be immediately subtracted again in setIdealFootprint().
1237 * If the target heap size would exceed the max, setIdealFootprint()
1238 * will clamp it to a legal value.
1239 */
1240 overhead = getSoftFootprint(false);
1241 oldIdealSize = hs->idealSize;
1242 setIdealFootprint(targetHeapSize + overhead);
1243
1244 newHeapMax = mspace_max_allowed_footprint(heap->msp);
1245 if (softLimited(hs)) {
1246 LOGD_HEAP("GC old usage %zd.%zd%%; now "
1247 "%zd.%03zdMB used / %zd.%03zdMB soft max "
1248 "(%zd.%03zdMB over, "
1249 "%zd.%03zdMB ext, "
1250 "%zd.%03zdMB real max)\n",
1251 FRACTIONAL_PCT(currentHeapUsed, oldIdealSize),
1252 FRACTIONAL_MB(currentHeapUsed),
1253 FRACTIONAL_MB(hs->softLimit),
1254 FRACTIONAL_MB(overhead),
1255 FRACTIONAL_MB(hs->externalBytesAllocated),
1256 FRACTIONAL_MB(newHeapMax));
1257 } else {
1258 LOGD_HEAP("GC old usage %zd.%zd%%; now "
1259 "%zd.%03zdMB used / %zd.%03zdMB real max "
1260 "(%zd.%03zdMB over, "
1261 "%zd.%03zdMB ext)\n",
1262 FRACTIONAL_PCT(currentHeapUsed, oldIdealSize),
1263 FRACTIONAL_MB(currentHeapUsed),
1264 FRACTIONAL_MB(newHeapMax),
1265 FRACTIONAL_MB(overhead),
1266 FRACTIONAL_MB(hs->externalBytesAllocated));
1267 }
1268}
1269
1270/*
1271 * Return free pages to the system.
1272 * TODO: move this somewhere else, especially the native heap part.
1273 */
1274
1275static void releasePagesInRange(void *start, void *end, void *nbytes)
1276{
1277 /* Linux requires that the madvise() start address is page-aligned.
1278 * We also align the end address.
1279 */
1280 start = (void *)ALIGN_UP_TO_PAGE_SIZE(start);
Andy McFadden96516932009-10-28 17:39:02 -07001281 end = (void *)((size_t)end & ~(SYSTEM_PAGE_SIZE - 1));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001282 if (start < end) {
1283 size_t length = (char *)end - (char *)start;
1284 madvise(start, length, MADV_DONTNEED);
1285 *(size_t *)nbytes += length;
1286 }
1287}
1288
1289/*
1290 * Return unused memory to the system if possible.
1291 */
1292void
1293dvmHeapSourceTrim(size_t bytesTrimmed[], size_t arrayLen)
1294{
1295 HeapSource *hs = gHs;
1296 size_t nativeBytes, heapBytes;
1297 size_t i;
1298
1299 HS_BOILERPLATE();
1300
1301 assert(arrayLen >= hs->numHeaps);
1302
1303 heapBytes = 0;
1304 for (i = 0; i < hs->numHeaps; i++) {
1305 Heap *heap = &hs->heaps[i];
1306
1307 /* Return the wilderness chunk to the system.
1308 */
1309 mspace_trim(heap->msp, 0);
1310
1311 /* Return any whole free pages to the system.
1312 */
1313 bytesTrimmed[i] = 0;
1314 mspace_walk_free_pages(heap->msp, releasePagesInRange,
1315 &bytesTrimmed[i]);
1316 heapBytes += bytesTrimmed[i];
1317 }
1318
1319 /* Same for the native heap.
1320 */
1321 dlmalloc_trim(0);
1322 nativeBytes = 0;
1323 dlmalloc_walk_free_pages(releasePagesInRange, &nativeBytes);
1324
1325 LOGD_HEAP("madvised %zd (GC) + %zd (native) = %zd total bytes\n",
1326 heapBytes, nativeBytes, heapBytes + nativeBytes);
1327}
1328
1329/*
1330 * Walks over the heap source and passes every allocated and
1331 * free chunk to the callback.
1332 */
1333void
1334dvmHeapSourceWalk(void(*callback)(const void *chunkptr, size_t chunklen,
1335 const void *userptr, size_t userlen,
1336 void *arg),
1337 void *arg)
1338{
1339 HeapSource *hs = gHs;
1340 size_t i;
1341
1342 HS_BOILERPLATE();
1343
1344 /* Walk the heaps from oldest to newest.
1345 */
1346//TODO: do this in address order
1347 for (i = hs->numHeaps; i > 0; --i) {
1348 mspace_walk_heap(hs->heaps[i-1].msp, callback, arg);
1349 }
1350}
1351
1352/*
1353 * Gets the number of heaps available in the heap source.
1354 *
1355 * Caller must hold the heap lock, because gHs caches a field
1356 * in gDvm.gcHeap.
1357 */
1358size_t
1359dvmHeapSourceGetNumHeaps()
1360{
1361 HeapSource *hs = gHs;
1362
1363 HS_BOILERPLATE();
1364
1365 return hs->numHeaps;
1366}
1367
1368
1369/*
1370 * External allocation tracking
1371 *
1372 * In some situations, memory outside of the heap is tied to the
1373 * lifetime of objects in the heap. Since that memory is kept alive
1374 * by heap objects, it should provide memory pressure that can influence
1375 * GCs.
1376 */
1377
1378
1379static bool
1380externalAllocPossible(const HeapSource *hs, size_t n)
1381{
1382 const Heap *heap;
1383 size_t currentHeapSize;
1384
1385 /* Make sure that this allocation is even possible.
1386 * Don't let the external size plus the actual heap size
1387 * go over the absolute max. This essentially treats
1388 * external allocations as part of the active heap.
1389 *
1390 * Note that this will fail "mysteriously" if there's
1391 * a small softLimit but a large heap footprint.
1392 */
1393 heap = hs2heap(hs);
1394 currentHeapSize = mspace_max_allowed_footprint(heap->msp);
1395 if (currentHeapSize + hs->externalBytesAllocated + n <=
1396 heap->absoluteMaxSize)
1397 {
1398 return true;
1399 }
1400 HSTRACE("externalAllocPossible(): "
1401 "footprint %zu + extAlloc %zu + n %zu >= max %zu (space for %zu)\n",
1402 currentHeapSize, hs->externalBytesAllocated, n,
1403 heap->absoluteMaxSize,
1404 heap->absoluteMaxSize -
1405 (currentHeapSize + hs->externalBytesAllocated));
1406 return false;
1407}
1408
1409#define EXTERNAL_TARGET_UTILIZATION 820 // 80%
1410
1411/*
1412 * Tries to update the internal count of externally-allocated memory.
1413 * If there's enough room for that memory, returns true. If not, returns
1414 * false and does not update the count.
1415 *
1416 * The caller must ensure externalAllocPossible(hs, n) == true.
1417 */
1418static bool
1419externalAlloc(HeapSource *hs, size_t n, bool grow)
1420{
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001421 assert(hs->externalLimit >= hs->externalBytesAllocated);
1422
1423 HSTRACE("externalAlloc(%zd%s)\n", n, grow ? ", grow" : "");
1424 assert(externalAllocPossible(hs, n)); // The caller must ensure this.
1425
1426 /* External allocations have their own "free space" that they
1427 * can allocate from without causing a GC.
1428 */
1429 if (hs->externalBytesAllocated + n <= hs->externalLimit) {
1430 hs->externalBytesAllocated += n;
1431#if defined(WITH_PROFILER) && PROFILE_EXTERNAL_ALLOCATIONS
1432 if (gDvm.allocProf.enabled) {
1433 Thread* self = dvmThreadSelf();
1434 gDvm.allocProf.externalAllocCount++;
1435 gDvm.allocProf.externalAllocSize += n;
1436 if (self != NULL) {
1437 self->allocProf.externalAllocCount++;
1438 self->allocProf.externalAllocSize += n;
1439 }
1440 }
1441#endif
1442 return true;
1443 }
1444 if (!grow) {
1445 return false;
1446 }
1447
1448 /* GROW */
1449 hs->externalBytesAllocated += n;
Carl Shapiro98389d02010-02-14 23:11:47 -08001450 hs->externalLimit = getUtilizationTarget(
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001451 hs->externalBytesAllocated, EXTERNAL_TARGET_UTILIZATION);
1452 HSTRACE("EXTERNAL grow limit to %zd\n", hs->externalLimit);
1453 return true;
1454}
1455
1456static void
1457gcForExternalAlloc(bool collectSoftReferences)
1458{
1459#ifdef WITH_PROFILER // even if !PROFILE_EXTERNAL_ALLOCATIONS
1460 if (gDvm.allocProf.enabled) {
1461 Thread* self = dvmThreadSelf();
1462 gDvm.allocProf.gcCount++;
1463 if (self != NULL) {
1464 self->allocProf.gcCount++;
1465 }
1466 }
1467#endif
Barry Hayes1b9b4e42010-01-04 10:33:46 -08001468 dvmCollectGarbageInternal(collectSoftReferences, GC_EXTERNAL_ALLOC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001469}
1470
1471/*
1472 * Updates the internal count of externally-allocated memory. If there's
1473 * enough room for that memory, returns true. If not, returns false and
1474 * does not update the count.
1475 *
1476 * May cause a GC as a side-effect.
1477 */
1478bool
1479dvmTrackExternalAllocation(size_t n)
1480{
1481 HeapSource *hs = gHs;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001482 bool ret = false;
1483
1484 /* gHs caches an entry in gDvm.gcHeap; we need to hold the
1485 * heap lock if we're going to look at it.
1486 */
1487 dvmLockHeap();
1488
1489 HS_BOILERPLATE();
1490 assert(hs->externalLimit >= hs->externalBytesAllocated);
1491
1492 if (!externalAllocPossible(hs, n)) {
1493 LOGE_HEAP("%zd-byte external allocation "
1494 "too large for this process.\n", n);
1495 goto out;
1496 }
1497
1498 /* Try "allocating" using the existing "free space".
1499 */
1500 HSTRACE("EXTERNAL alloc %zu (%zu < %zu)\n",
1501 n, hs->externalBytesAllocated, hs->externalLimit);
1502 if (externalAlloc(hs, n, false)) {
1503 ret = true;
1504 goto out;
1505 }
1506
1507 /* The "allocation" failed. Free up some space by doing
1508 * a full garbage collection. This may grow the heap source
1509 * if the live set is sufficiently large.
1510 */
1511 HSTRACE("EXTERNAL alloc %zd: GC 1\n", n);
1512 gcForExternalAlloc(false); // don't collect SoftReferences
1513 if (externalAlloc(hs, n, false)) {
1514 ret = true;
1515 goto out;
1516 }
1517
1518 /* Even that didn't work; this is an exceptional state.
1519 * Try harder, growing the heap source if necessary.
1520 */
1521 HSTRACE("EXTERNAL alloc %zd: frag\n", n);
1522 ret = externalAlloc(hs, n, true);
1523 dvmHeapSizeChanged();
1524 if (ret) {
1525 goto out;
1526 }
1527
1528 /* We couldn't even grow enough to satisfy the request.
1529 * Try one last GC, collecting SoftReferences this time.
1530 */
1531 HSTRACE("EXTERNAL alloc %zd: GC 2\n", n);
1532 gcForExternalAlloc(true); // collect SoftReferences
1533 ret = externalAlloc(hs, n, true);
1534 dvmHeapSizeChanged();
1535 if (!ret) {
1536 LOGE_HEAP("Out of external memory on a %zu-byte allocation.\n", n);
1537 }
1538
1539#if defined(WITH_PROFILER) && PROFILE_EXTERNAL_ALLOCATIONS
1540 if (gDvm.allocProf.enabled) {
1541 Thread* self = dvmThreadSelf();
1542 gDvm.allocProf.failedExternalAllocCount++;
1543 gDvm.allocProf.failedExternalAllocSize += n;
1544 if (self != NULL) {
1545 self->allocProf.failedExternalAllocCount++;
1546 self->allocProf.failedExternalAllocSize += n;
1547 }
1548 }
1549#endif
1550
1551out:
1552 dvmUnlockHeap();
1553
1554 return ret;
1555}
1556
1557/*
1558 * Reduces the internal count of externally-allocated memory.
1559 */
1560void
1561dvmTrackExternalFree(size_t n)
1562{
1563 HeapSource *hs = gHs;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001564 size_t newExternalLimit;
1565 size_t oldExternalBytesAllocated;
1566
1567 HSTRACE("EXTERNAL free %zu (%zu < %zu)\n",
1568 n, hs->externalBytesAllocated, hs->externalLimit);
1569
1570 /* gHs caches an entry in gDvm.gcHeap; we need to hold the
1571 * heap lock if we're going to look at it.
1572 */
1573 dvmLockHeap();
1574
1575 HS_BOILERPLATE();
1576 assert(hs->externalLimit >= hs->externalBytesAllocated);
1577
1578 oldExternalBytesAllocated = hs->externalBytesAllocated;
1579 if (n <= hs->externalBytesAllocated) {
1580 hs->externalBytesAllocated -= n;
1581 } else {
1582 n = hs->externalBytesAllocated;
1583 hs->externalBytesAllocated = 0;
1584 }
1585
1586#if defined(WITH_PROFILER) && PROFILE_EXTERNAL_ALLOCATIONS
1587 if (gDvm.allocProf.enabled) {
1588 Thread* self = dvmThreadSelf();
1589 gDvm.allocProf.externalFreeCount++;
1590 gDvm.allocProf.externalFreeSize += n;
1591 if (self != NULL) {
1592 self->allocProf.externalFreeCount++;
1593 self->allocProf.externalFreeSize += n;
1594 }
1595 }
1596#endif
1597
1598 /* Shrink as quickly as we can.
1599 */
Carl Shapiro98389d02010-02-14 23:11:47 -08001600 newExternalLimit = getUtilizationTarget(
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001601 hs->externalBytesAllocated, EXTERNAL_TARGET_UTILIZATION);
1602 if (newExternalLimit < oldExternalBytesAllocated) {
1603 /* Make sure that the remaining free space is at least
1604 * big enough to allocate something of the size that was
1605 * just freed. This makes it more likely that
1606 * externalFree(N); externalAlloc(N);
1607 * will work without causing a GC.
1608 */
1609 HSTRACE("EXTERNAL free preserved %zu extra free bytes\n",
1610 oldExternalBytesAllocated - newExternalLimit);
1611 newExternalLimit = oldExternalBytesAllocated;
1612 }
1613 if (newExternalLimit < hs->externalLimit) {
1614 hs->externalLimit = newExternalLimit;
1615 }
1616
1617 dvmUnlockHeap();
1618}
1619
1620/*
1621 * Returns the number of externally-allocated bytes being tracked by
1622 * dvmTrackExternalAllocation/Free().
1623 */
1624size_t
1625dvmGetExternalBytesAllocated()
1626{
1627 const HeapSource *hs = gHs;
1628 size_t ret;
1629
1630 /* gHs caches an entry in gDvm.gcHeap; we need to hold the
1631 * heap lock if we're going to look at it. We also need the
1632 * lock for the call to setIdealFootprint().
1633 */
1634 dvmLockHeap();
1635 HS_BOILERPLATE();
1636 ret = hs->externalBytesAllocated;
1637 dvmUnlockHeap();
1638
1639 return ret;
1640}