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