blob: e58a8a8c8bd7aeaa03ebdfab3a4144335be339a4 [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 * Garbage-collecting memory allocator.
18 */
19#include "Dalvik.h"
20#include "alloc/HeapTable.h"
21#include "alloc/Heap.h"
22#include "alloc/HeapInternal.h"
23#include "alloc/DdmHeap.h"
24#include "alloc/HeapSource.h"
25#include "alloc/MarkSweep.h"
26
27#include "utils/threads.h" // need Android thread priorities
28#define kInvalidPriority 10000
29
30#include <sys/time.h>
31#include <sys/resource.h>
32#include <limits.h>
33#include <errno.h>
34
35#define kNonCollectableRefDefault 16
36#define kFinalizableRefDefault 128
37
38/*
39 * Initialize the GC heap.
40 *
41 * Returns true if successful, false otherwise.
42 */
43bool dvmHeapStartup()
44{
45 GcHeap *gcHeap;
46
47#if defined(WITH_ALLOC_LIMITS)
48 gDvm.checkAllocLimits = false;
49 gDvm.allocationLimit = -1;
50#endif
51
52 gcHeap = dvmHeapSourceStartup(gDvm.heapSizeStart, gDvm.heapSizeMax);
53 if (gcHeap == NULL) {
54 return false;
55 }
56 gcHeap->heapWorkerCurrentObject = NULL;
57 gcHeap->heapWorkerCurrentMethod = NULL;
58 gcHeap->heapWorkerInterpStartTime = 0LL;
59 gcHeap->softReferenceCollectionState = SR_COLLECT_NONE;
60 gcHeap->softReferenceHeapSizeThreshold = gDvm.heapSizeStart;
61 gcHeap->ddmHpifWhen = 0;
62 gcHeap->ddmHpsgWhen = 0;
63 gcHeap->ddmHpsgWhat = 0;
64 gcHeap->ddmNhsgWhen = 0;
65 gcHeap->ddmNhsgWhat = 0;
66#if WITH_HPROF
67 gcHeap->hprofDumpOnGc = false;
68 gcHeap->hprofContext = NULL;
69#endif
70
71 /* This needs to be set before we call dvmHeapInitHeapRefTable().
72 */
73 gDvm.gcHeap = gcHeap;
74
75 /* Set up the table we'll use for ALLOC_NO_GC.
76 */
77 if (!dvmHeapInitHeapRefTable(&gcHeap->nonCollectableRefs,
78 kNonCollectableRefDefault))
79 {
80 LOGE_HEAP("Can't allocate GC_NO_ALLOC table\n");
81 goto fail;
82 }
83
84 /* Set up the lists and lock we'll use for finalizable
85 * and reference objects.
86 */
87 dvmInitMutex(&gDvm.heapWorkerListLock);
88 gcHeap->finalizableRefs = NULL;
89 gcHeap->pendingFinalizationRefs = NULL;
90 gcHeap->referenceOperations = NULL;
91
92 /* Initialize the HeapWorker locks and other state
93 * that the GC uses.
94 */
95 dvmInitializeHeapWorkerState();
96
97 return true;
98
99fail:
100 gDvm.gcHeap = NULL;
101 dvmHeapSourceShutdown(gcHeap);
102 return false;
103}
104
105bool dvmHeapStartupAfterZygote()
106{
107 /* Update our idea of the last GC start time so that we
108 * don't use the last time that Zygote happened to GC.
109 */
110 gDvm.gcHeap->gcStartTime = dvmGetRelativeTimeUsec();
111
112 return dvmHeapSourceStartupAfterZygote();
113}
114
115void dvmHeapShutdown()
116{
117//TODO: make sure we're locked
118 if (gDvm.gcHeap != NULL) {
119 GcHeap *gcHeap;
120
121 gcHeap = gDvm.gcHeap;
122 gDvm.gcHeap = NULL;
123
124 /* Tables are allocated on the native heap;
125 * they need to be cleaned up explicitly.
126 * The process may stick around, so we don't
127 * want to leak any native memory.
128 */
129 dvmHeapFreeHeapRefTable(&gcHeap->nonCollectableRefs);
130
131 dvmHeapFreeLargeTable(gcHeap->finalizableRefs);
132 gcHeap->finalizableRefs = NULL;
133
134 dvmHeapFreeLargeTable(gcHeap->pendingFinalizationRefs);
135 gcHeap->pendingFinalizationRefs = NULL;
136
137 dvmHeapFreeLargeTable(gcHeap->referenceOperations);
138 gcHeap->referenceOperations = NULL;
139
140 /* Destroy the heap. Any outstanding pointers
141 * will point to unmapped memory (unless/until
142 * someone else maps it). This frees gcHeap
143 * as a side-effect.
144 */
145 dvmHeapSourceShutdown(gcHeap);
146 }
147}
148
149/*
150 * We've been asked to allocate something we can't, e.g. an array so
151 * large that (length * elementWidth) is larger than 2^31. We want to
152 * throw an OutOfMemoryError, but doing so implies that certain other
153 * actions have taken place (like clearing soft references).
154 *
155 * TODO: for now we just throw an InternalError.
156 */
157void dvmThrowBadAllocException(const char* msg)
158{
159 dvmThrowException("Ljava/lang/InternalError;", msg);
160}
161
162/*
163 * Grab the lock, but put ourselves into THREAD_VMWAIT if it looks like
164 * we're going to have to wait on the mutex.
165 */
166bool dvmLockHeap()
167{
168 if (pthread_mutex_trylock(&gDvm.gcHeapLock) != 0) {
169 Thread *self;
170 ThreadStatus oldStatus;
171 int cc;
172
173 self = dvmThreadSelf();
174 if (self != NULL) {
175 oldStatus = dvmChangeStatus(self, THREAD_VMWAIT);
176 } else {
177 oldStatus = -1; // shut up gcc
178 }
179
180 cc = pthread_mutex_lock(&gDvm.gcHeapLock);
181 assert(cc == 0);
182
183 if (self != NULL) {
184 dvmChangeStatus(self, oldStatus);
185 }
186 }
187
188 return true;
189}
190
191void dvmUnlockHeap()
192{
193 dvmUnlockMutex(&gDvm.gcHeapLock);
194}
195
196/* Pop an object from the list of pending finalizations and
197 * reference clears/enqueues, and return the object.
198 * The caller must call dvmReleaseTrackedAlloc()
199 * on the object when finished.
200 *
201 * Typically only called by the heap worker thread.
202 */
203Object *dvmGetNextHeapWorkerObject(HeapWorkerOperation *op)
204{
205 Object *obj;
206 LargeHeapRefTable *table;
207 GcHeap *gcHeap = gDvm.gcHeap;
208
209 assert(op != NULL);
210
211 obj = NULL;
212
213 dvmLockMutex(&gDvm.heapWorkerListLock);
214
215 /* We must handle reference operations before finalizations.
216 * If:
217 * a) Someone subclasses WeakReference and overrides clear()
218 * b) A reference of this type is the last reference to
219 * a finalizable object
220 * then we need to guarantee that the overridden clear() is called
221 * on the reference before finalize() is called on the referent.
222 * Both of these operations will always be scheduled at the same
223 * time, so handling reference operations first will guarantee
224 * the required order.
225 */
226 obj = dvmHeapGetNextObjectFromLargeTable(&gcHeap->referenceOperations);
227 if (obj != NULL) {
228 uintptr_t workBits;
229
230 workBits = (uintptr_t)obj & (WORKER_CLEAR | WORKER_ENQUEUE);
231 assert(workBits != 0);
232 obj = (Object *)((uintptr_t)obj & ~(WORKER_CLEAR | WORKER_ENQUEUE));
233
234 *op = workBits;
235 } else {
236 obj = dvmHeapGetNextObjectFromLargeTable(
237 &gcHeap->pendingFinalizationRefs);
238 if (obj != NULL) {
239 *op = WORKER_FINALIZE;
240 }
241 }
242
243 if (obj != NULL) {
244 /* Don't let the GC collect the object until the
245 * worker thread is done with it.
246 *
247 * This call is safe; it uses thread-local storage
248 * and doesn't acquire any locks.
249 */
250 dvmAddTrackedAlloc(obj, NULL);
251 }
252
253 dvmUnlockMutex(&gDvm.heapWorkerListLock);
254
255 return obj;
256}
257
258/* Used for a heap size change hysteresis to avoid collecting
259 * SoftReferences when the heap only grows by a small amount.
260 */
261#define SOFT_REFERENCE_GROWTH_SLACK (128 * 1024)
262
263/* Whenever the effective heap size may have changed,
264 * this function must be called.
265 */
266void dvmHeapSizeChanged()
267{
268 GcHeap *gcHeap = gDvm.gcHeap;
269 size_t currentHeapSize;
270
271 currentHeapSize = dvmHeapSourceGetIdealFootprint();
272
273 /* See if the heap size has changed enough that we should care
274 * about it.
275 */
276 if (currentHeapSize <= gcHeap->softReferenceHeapSizeThreshold -
277 4 * SOFT_REFERENCE_GROWTH_SLACK)
278 {
279 /* The heap has shrunk enough that we'll use this as a new
280 * threshold. Since we're doing better on space, there's
281 * no need to collect any SoftReferences.
282 *
283 * This is 4x the growth hysteresis because we don't want
284 * to snap down so easily after a shrink. If we just cleared
285 * up a bunch of SoftReferences, we don't want to disallow
286 * any new ones from being created.
287 * TODO: determine if the 4x is important, needed, or even good
288 */
289 gcHeap->softReferenceHeapSizeThreshold = currentHeapSize;
290 gcHeap->softReferenceCollectionState = SR_COLLECT_NONE;
291 } else if (currentHeapSize >= gcHeap->softReferenceHeapSizeThreshold +
292 SOFT_REFERENCE_GROWTH_SLACK)
293 {
294 /* The heap has grown enough to warrant collecting SoftReferences.
295 */
296 gcHeap->softReferenceHeapSizeThreshold = currentHeapSize;
297 gcHeap->softReferenceCollectionState = SR_COLLECT_SOME;
298 }
299}
300
301
302/* Do a full garbage collection, which may grow the
303 * heap as a side-effect if the live set is large.
304 */
305static void gcForMalloc(bool collectSoftReferences)
306{
307#ifdef WITH_PROFILER
308 if (gDvm.allocProf.enabled) {
309 Thread* self = dvmThreadSelf();
310 gDvm.allocProf.gcCount++;
311 if (self != NULL) {
312 self->allocProf.gcCount++;
313 }
314 }
315#endif
316 /* This may adjust the soft limit as a side-effect.
317 */
318 LOGD_HEAP("dvmMalloc initiating GC%s\n",
319 collectSoftReferences ? "(collect SoftReferences)" : "");
320 dvmCollectGarbageInternal(collectSoftReferences);
321}
322
323/* Try as hard as possible to allocate some memory.
324 */
325static DvmHeapChunk *tryMalloc(size_t size)
326{
327 DvmHeapChunk *hc;
328
329 /* Don't try too hard if there's no way the allocation is
330 * going to succeed. We have to collect SoftReferences before
331 * throwing an OOME, though.
332 */
333 if (size >= gDvm.heapSizeMax) {
334 LOGW_HEAP("dvmMalloc(%zu/0x%08zx): "
335 "someone's allocating a huge buffer\n", size, size);
336 hc = NULL;
337 goto collect_soft_refs;
338 }
339
340//TODO: figure out better heuristics
341// There will be a lot of churn if someone allocates a bunch of
342// big objects in a row, and we hit the frag case each time.
343// A full GC for each.
344// Maybe we grow the heap in bigger leaps
345// Maybe we skip the GC if the size is large and we did one recently
346// (number of allocations ago) (watch for thread effects)
347// DeflateTest allocs a bunch of ~128k buffers w/in 0-5 allocs of each other
348// (or, at least, there are only 0-5 objects swept each time)
349
350 hc = dvmHeapSourceAlloc(size + sizeof(DvmHeapChunk));
351 if (hc != NULL) {
352 return hc;
353 }
354
355 /* The allocation failed. Free up some space by doing
356 * a full garbage collection. This may grow the heap
357 * if the live set is sufficiently large.
358 */
359 gcForMalloc(false);
360 hc = dvmHeapSourceAlloc(size + sizeof(DvmHeapChunk));
361 if (hc != NULL) {
362 return hc;
363 }
364
365 /* Even that didn't work; this is an exceptional state.
366 * Try harder, growing the heap if necessary.
367 */
368 hc = dvmHeapSourceAllocAndGrow(size + sizeof(DvmHeapChunk));
369 dvmHeapSizeChanged();
370 if (hc != NULL) {
371 size_t newHeapSize;
372
373 newHeapSize = dvmHeapSourceGetIdealFootprint();
374//TODO: may want to grow a little bit more so that the amount of free
375// space is equal to the old free space + the utilization slop for
376// the new allocation.
377 LOGI_HEAP("Grow heap (frag case) to "
378 "%zu.%03zuMB for %zu-byte allocation\n",
379 FRACTIONAL_MB(newHeapSize), size);
380 return hc;
381 }
382
383 /* Most allocations should have succeeded by now, so the heap
384 * is really full, really fragmented, or the requested size is
385 * really big. Do another GC, collecting SoftReferences this
386 * time. The VM spec requires that all SoftReferences have
387 * been collected and cleared before throwing an OOME.
388 */
389//TODO: wait for the finalizers from the previous GC to finish
390collect_soft_refs:
391 LOGI_HEAP("Forcing collection of SoftReferences for %zu-byte allocation\n",
392 size);
393 gcForMalloc(true);
394 hc = dvmHeapSourceAllocAndGrow(size + sizeof(DvmHeapChunk));
395 dvmHeapSizeChanged();
396 if (hc != NULL) {
397 return hc;
398 }
399//TODO: maybe wait for finalizers and try one last time
400
401 LOGE_HEAP("Out of memory on a %zd-byte allocation.\n", size);
402//TODO: tell the HeapSource to dump its state
403 dvmDumpThread(dvmThreadSelf(), false);
404
405 return NULL;
406}
407
408/* Throw an OutOfMemoryError if there's a thread to attach it to.
409 * Avoid recursing.
410 *
411 * The caller must not be holding the heap lock, or else the allocations
412 * in dvmThrowException() will deadlock.
413 */
414static void throwOOME()
415{
416 Thread *self;
417
418 if ((self = dvmThreadSelf()) != NULL) {
419 /* If the current (failing) dvmMalloc() happened as part of thread
420 * creation/attachment before the thread became part of the root set,
421 * we can't rely on the thread-local trackedAlloc table, so
422 * we can't keep track of a real allocated OOME object. But, since
423 * the thread is in the process of being created, it won't have
424 * a useful stack anyway, so we may as well make things easier
425 * by throwing the (stackless) pre-built OOME.
426 */
427 if (dvmIsOnThreadList(self) && !self->throwingOOME) {
428 /* Let ourselves know that we tried to throw an OOM
429 * error in the normal way in case we run out of
430 * memory trying to allocate it inside dvmThrowException().
431 */
432 self->throwingOOME = true;
433
434 /* Don't include a description string;
435 * one fewer allocation.
436 */
437 dvmThrowException("Ljava/lang/OutOfMemoryError;", NULL);
438 } else {
439 /*
440 * This thread has already tried to throw an OutOfMemoryError,
441 * which probably means that we're running out of memory
442 * while recursively trying to throw.
443 *
444 * To avoid any more allocation attempts, "throw" a pre-built
445 * OutOfMemoryError object (which won't have a useful stack trace).
446 *
447 * Note that since this call can't possibly allocate anything,
448 * we don't care about the state of self->throwingOOME
449 * (which will usually already be set).
450 */
451 dvmSetException(self, gDvm.outOfMemoryObj);
452 }
453 /* We're done with the possible recursion.
454 */
455 self->throwingOOME = false;
456 }
457}
458
459/*
460 * Allocate storage on the GC heap. We guarantee 8-byte alignment.
461 *
462 * The new storage is zeroed out.
463 *
464 * Note that, in rare cases, this could get called while a GC is in
465 * progress. If a non-VM thread tries to attach itself through JNI,
466 * it will need to allocate some objects. If this becomes annoying to
467 * deal with, we can block it at the source, but holding the allocation
468 * mutex should be enough.
469 *
470 * In rare circumstances (JNI AttachCurrentThread) we can be called
471 * from a non-VM thread.
472 *
473 * We implement ALLOC_NO_GC by maintaining an internal list of objects
474 * that should not be collected. This requires no actual flag storage in
475 * the object itself, which is good, but makes flag queries expensive.
476 *
477 * Use ALLOC_DONT_TRACK when we either don't want to track an allocation
478 * (because it's being done for the interpreter "new" operation and will
479 * be part of the root set immediately) or we can't (because this allocation
480 * is for a brand new thread).
481 *
482 * Returns NULL and throws an exception on failure.
483 *
484 * TODO: don't do a GC if the debugger thinks all threads are suspended
485 */
486void* dvmMalloc(size_t size, int flags)
487{
488 GcHeap *gcHeap = gDvm.gcHeap;
489 DvmHeapChunk *hc;
490 void *ptr;
491 bool triedGc, triedGrowing;
492
493#if 0
494 /* handy for spotting large allocations */
495 if (size >= 100000) {
496 LOGI("dvmMalloc(%d):\n", size);
497 dvmDumpThread(dvmThreadSelf(), false);
498 }
499#endif
500
501#if defined(WITH_ALLOC_LIMITS)
502 /*
503 * See if they've exceeded the allocation limit for this thread.
504 *
505 * A limit value of -1 means "no limit".
506 *
507 * This is enabled at compile time because it requires us to do a
508 * TLS lookup for the Thread pointer. This has enough of a performance
509 * impact that we don't want to do it if we don't have to. (Now that
510 * we're using gDvm.checkAllocLimits we may want to reconsider this,
511 * but it's probably still best to just compile the check out of
512 * production code -- one less thing to hit on every allocation.)
513 */
514 if (gDvm.checkAllocLimits) {
515 Thread* self = dvmThreadSelf();
516 if (self != NULL) {
517 int count = self->allocLimit;
518 if (count > 0) {
519 self->allocLimit--;
520 } else if (count == 0) {
521 /* fail! */
522 assert(!gDvm.initializing);
523 self->allocLimit = -1;
524 dvmThrowException("Ldalvik/system/AllocationLimitError;",
525 "thread allocation limit exceeded");
526 return NULL;
527 }
528 }
529 }
530
531 if (gDvm.allocationLimit >= 0) {
532 assert(!gDvm.initializing);
533 gDvm.allocationLimit = -1;
534 dvmThrowException("Ldalvik/system/AllocationLimitError;",
535 "global allocation limit exceeded");
536 return NULL;
537 }
538#endif
539
540 dvmLockHeap();
541
542 /* Try as hard as possible to allocate some memory.
543 */
544 hc = tryMalloc(size);
545 if (hc != NULL) {
546alloc_succeeded:
547 /* We've got the memory.
548 */
549 if ((flags & ALLOC_FINALIZABLE) != 0) {
550 /* This object is an instance of a class that
551 * overrides finalize(). Add it to the finalizable list.
552 *
553 * Note that until DVM_OBJECT_INIT() is called on this
554 * object, its clazz will be NULL. Since the object is
555 * in this table, it will be scanned as part of the root
556 * set. scanObject() explicitly deals with the NULL clazz.
557 */
558 if (!dvmHeapAddRefToLargeTable(&gcHeap->finalizableRefs,
559 (Object *)hc->data))
560 {
561 LOGE_HEAP("dvmMalloc(): no room for any more "
562 "finalizable objects\n");
563 dvmAbort();
564 }
565 }
566
567#if WITH_OBJECT_HEADERS
568 hc->header = OBJECT_HEADER;
569 hc->birthGeneration = gGeneration;
570#endif
571 ptr = hc->data;
572
573 /* The caller may not want us to collect this object.
574 * If not, throw it in the nonCollectableRefs table, which
575 * will be added to the root set when we GC.
576 *
577 * Note that until DVM_OBJECT_INIT() is called on this
578 * object, its clazz will be NULL. Since the object is
579 * in this table, it will be scanned as part of the root
580 * set. scanObject() explicitly deals with the NULL clazz.
581 */
582 if ((flags & ALLOC_NO_GC) != 0) {
583 if (!dvmHeapAddToHeapRefTable(&gcHeap->nonCollectableRefs, ptr)) {
584 LOGE_HEAP("dvmMalloc(): no room for any more "
585 "ALLOC_NO_GC objects: %zd\n",
586 dvmHeapNumHeapRefTableEntries(
587 &gcHeap->nonCollectableRefs));
588 dvmAbort();
589 }
590 }
591
592#ifdef WITH_PROFILER
593 if (gDvm.allocProf.enabled) {
594 Thread* self = dvmThreadSelf();
595 gDvm.allocProf.allocCount++;
596 gDvm.allocProf.allocSize += size;
597 if (self != NULL) {
598 self->allocProf.allocCount++;
599 self->allocProf.allocSize += size;
600 }
601 }
602#endif
603 } else {
604 /* The allocation failed.
605 */
606 ptr = NULL;
607
608#ifdef WITH_PROFILER
609 if (gDvm.allocProf.enabled) {
610 Thread* self = dvmThreadSelf();
611 gDvm.allocProf.failedAllocCount++;
612 gDvm.allocProf.failedAllocSize += size;
613 if (self != NULL) {
614 self->allocProf.failedAllocCount++;
615 self->allocProf.failedAllocSize += size;
616 }
617 }
618#endif
619 }
620
621 dvmUnlockHeap();
622
623 if (ptr != NULL) {
624 /*
625 * If this block is immediately GCable, and they haven't asked us not
626 * to track it, add it to the internal tracking list.
627 *
628 * If there's no "self" yet, we can't track it. Calls made before
629 * the Thread exists should use ALLOC_NO_GC.
630 */
631 if ((flags & (ALLOC_DONT_TRACK | ALLOC_NO_GC)) == 0) {
632 dvmAddTrackedAlloc(ptr, NULL);
633 }
634 } else {
635 /*
636 * The allocation failed; throw an OutOfMemoryError.
637 */
638 throwOOME();
639 }
640
641 return ptr;
642}
643
644/*
645 * Returns true iff <obj> points to a valid allocated object.
646 */
647bool dvmIsValidObject(const Object* obj)
648{
649 const DvmHeapChunk *hc;
650
651 /* Don't bother if it's NULL or not 8-byte aligned.
652 */
653 hc = ptr2chunk(obj);
654 if (obj != NULL && ((uintptr_t)hc & (8-1)) == 0) {
655 /* Even if the heap isn't locked, this shouldn't return
656 * any false negatives. The only mutation that could
657 * be happening is allocation, which means that another
658 * thread could be in the middle of a read-modify-write
659 * to add a new bit for a new object. However, that
660 * RMW will have completed by the time any other thread
661 * could possibly see the new pointer, so there is no
662 * danger of dvmIsValidObject() being called on a valid
663 * pointer whose bit isn't set.
664 *
665 * Freeing will only happen during the sweep phase, which
666 * only happens while the heap is locked.
667 */
668 return dvmHeapSourceContains(hc);
669 }
670 return false;
671}
672
673/*
674 * Clear flags that were passed into dvmMalloc() et al.
675 * e.g., ALLOC_NO_GC, ALLOC_DONT_TRACK.
676 */
677void dvmClearAllocFlags(Object *obj, int mask)
678{
679 if ((mask & ALLOC_NO_GC) != 0) {
680 dvmLockHeap();
681 if (dvmIsValidObject(obj)) {
682 if (!dvmHeapRemoveFromHeapRefTable(&gDvm.gcHeap->nonCollectableRefs,
683 obj))
684 {
685 LOGE_HEAP("dvmMalloc(): failed to remove ALLOC_NO_GC bit from "
686 "object 0x%08x\n", (uintptr_t)obj);
687 dvmAbort();
688 }
689//TODO: shrink if the table is very empty
690 }
691 dvmUnlockHeap();
692 }
693
694 if ((mask & ALLOC_DONT_TRACK) != 0) {
695 dvmReleaseTrackedAlloc(obj, NULL);
696 }
697}
698
699size_t dvmObjectSizeInHeap(const Object *obj)
700{
701 return dvmHeapSourceChunkSize(ptr2chunk(obj)) - sizeof(DvmHeapChunk);
702}
703
704/*
705 * Initiate garbage collection.
706 *
707 * NOTES:
708 * - If we don't hold gDvm.threadListLock, it's possible for a thread to
709 * be added to the thread list while we work. The thread should NOT
710 * start executing, so this is only interesting when we start chasing
711 * thread stacks. (Before we do so, grab the lock.)
712 *
713 * We are not allowed to GC when the debugger has suspended the VM, which
714 * is awkward because debugger requests can cause allocations. The easiest
715 * way to enforce this is to refuse to GC on an allocation made by the
716 * JDWP thread -- we have to expand the heap or fail.
717 */
718void dvmCollectGarbageInternal(bool collectSoftReferences)
719{
720 GcHeap *gcHeap = gDvm.gcHeap;
721 Object *softReferences;
722 Object *weakReferences;
723 Object *phantomReferences;
724
725 u8 now;
726 s8 timeSinceLastGc;
727 s8 gcElapsedTime;
728 int numFreed;
729 size_t sizeFreed;
730
731#if DVM_TRACK_HEAP_MARKING
732 /* Since weak and soft references are always cleared,
733 * they don't require any marking.
734 * (Soft are lumped into strong when they aren't cleared.)
735 */
736 size_t strongMarkCount = 0;
737 size_t strongMarkSize = 0;
738 size_t finalizeMarkCount = 0;
739 size_t finalizeMarkSize = 0;
740 size_t phantomMarkCount = 0;
741 size_t phantomMarkSize = 0;
742#endif
743
744 /* The heap lock must be held.
745 */
746
747 if (gcHeap->gcRunning) {
748 LOGW_HEAP("Attempted recursive GC\n");
749 return;
750 }
751 gcHeap->gcRunning = true;
752 now = dvmGetRelativeTimeUsec();
753 if (gcHeap->gcStartTime != 0) {
754 timeSinceLastGc = (now - gcHeap->gcStartTime) / 1000;
755 } else {
756 timeSinceLastGc = 0;
757 }
758 gcHeap->gcStartTime = now;
759
760 LOGV_HEAP("GC starting -- suspending threads\n");
761
762 dvmSuspendAllThreads(SUSPEND_FOR_GC);
763
764 /* Get the priority (the "nice" value) of the current thread. The
765 * getpriority() call can legitimately return -1, so we have to
766 * explicitly test errno.
767 */
768 errno = 0;
769 int oldThreadPriority = kInvalidPriority;
770 int priorityResult = getpriority(PRIO_PROCESS, 0);
771 if (errno != 0) {
772 LOGI_HEAP("getpriority(self) failed: %s\n", strerror(errno));
773 } else if (priorityResult > ANDROID_PRIORITY_NORMAL) {
774 /* Current value is numerically greater than "normal", which
775 * in backward UNIX terms means lower priority.
776 */
San Mehat256fc152009-04-21 14:03:06 -0700777
San Mehat3e371e22009-06-26 08:36:16 -0700778 if (priorityResult >= ANDROID_PRIORITY_BACKGROUND) {
San Mehat256fc152009-04-21 14:03:06 -0700779 dvmChangeThreadSchedulerGroup(NULL);
780 }
781
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800782 if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL) != 0) {
783 LOGI_HEAP("Unable to elevate priority from %d to %d\n",
784 priorityResult, ANDROID_PRIORITY_NORMAL);
785 } else {
786 /* priority elevated; save value so we can restore it later */
787 LOGD_HEAP("Elevating priority from %d to %d\n",
788 priorityResult, ANDROID_PRIORITY_NORMAL);
789 oldThreadPriority = priorityResult;
790 }
791 }
792
793 /* Wait for the HeapWorker thread to block.
794 * (It may also already be suspended in interp code,
795 * in which case it's not holding heapWorkerLock.)
796 */
797 dvmLockMutex(&gDvm.heapWorkerLock);
798
799 /* Make sure that the HeapWorker thread hasn't become
800 * wedged inside interp code. If it has, this call will
801 * print a message and abort the VM.
802 */
803 dvmAssertHeapWorkerThreadRunning();
804
805 /* Lock the pendingFinalizationRefs list.
806 *
807 * Acquire the lock after suspending so the finalizer
808 * thread can't block in the RUNNING state while
809 * we try to suspend.
810 */
811 dvmLockMutex(&gDvm.heapWorkerListLock);
812
813#ifdef WITH_PROFILER
814 dvmMethodTraceGCBegin();
815#endif
816
817#if WITH_HPROF
818
819/* Set DUMP_HEAP_ON_DDMS_UPDATE to 1 to enable heap dumps
820 * whenever DDMS requests a heap update (HPIF chunk).
821 * The output files will appear in /data/misc, which must
822 * already exist.
823 * You must define "WITH_HPROF := true" in your buildspec.mk
824 * and recompile libdvm for this to work.
825 *
826 * To enable stack traces for each allocation, define
827 * "WITH_HPROF_STACK := true" in buildspec.mk. This option slows down
828 * allocations and also requires 8 additional bytes per object on the
829 * GC heap.
830 */
831#define DUMP_HEAP_ON_DDMS_UPDATE 0
832#if DUMP_HEAP_ON_DDMS_UPDATE
833 gcHeap->hprofDumpOnGc |= (gcHeap->ddmHpifWhen != 0);
834#endif
835
836 if (gcHeap->hprofDumpOnGc) {
837 char nameBuf[128];
838
Andy McFadden8c880b92009-03-24 18:15:56 -0700839 gcHeap->hprofResult = -1;
840
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800841 if (gcHeap->hprofFileName == NULL) {
842 /* no filename was provided; invent one */
843 sprintf(nameBuf, "/data/misc/heap-dump-tm%d-pid%d.hprof",
844 (int) time(NULL), (int) getpid());
845 gcHeap->hprofFileName = nameBuf;
846 }
847 gcHeap->hprofContext = hprofStartup(gcHeap->hprofFileName);
848 if (gcHeap->hprofContext != NULL) {
849 hprofStartHeapDump(gcHeap->hprofContext);
850 }
851 gcHeap->hprofDumpOnGc = false;
852 gcHeap->hprofFileName = NULL;
853 }
854#endif
855
856 if (timeSinceLastGc < 10000) {
857 LOGD_HEAP("GC! (%dms since last GC)\n",
858 (int)timeSinceLastGc);
859 } else {
860 LOGD_HEAP("GC! (%d sec since last GC)\n",
861 (int)(timeSinceLastGc / 1000));
862 }
863#if DVM_TRACK_HEAP_MARKING
864 gcHeap->markCount = 0;
865 gcHeap->markSize = 0;
866#endif
867
868 /* Set up the marking context.
869 */
870 dvmHeapBeginMarkStep();
871
872 /* Mark the set of objects that are strongly reachable from the roots.
873 */
874 LOGD_HEAP("Marking...");
875 dvmHeapMarkRootSet();
876
877 /* dvmHeapScanMarkedObjects() will build the lists of known
878 * instances of the Reference classes.
879 */
880 gcHeap->softReferences = NULL;
881 gcHeap->weakReferences = NULL;
882 gcHeap->phantomReferences = NULL;
883
884 /* Make sure that we don't hard-mark the referents of Reference
885 * objects by default.
886 */
887 gcHeap->markAllReferents = false;
888
889 /* Don't mark SoftReferences if our caller wants us to collect them.
890 * This has to be set before calling dvmHeapScanMarkedObjects().
891 */
892 if (collectSoftReferences) {
893 gcHeap->softReferenceCollectionState = SR_COLLECT_ALL;
894 }
895
896 /* Recursively mark any objects that marked objects point to strongly.
897 * If we're not collecting soft references, soft-reachable
898 * objects will also be marked.
899 */
900 LOGD_HEAP("Recursing...");
901 dvmHeapScanMarkedObjects();
902#if DVM_TRACK_HEAP_MARKING
903 strongMarkCount = gcHeap->markCount;
904 strongMarkSize = gcHeap->markSize;
905 gcHeap->markCount = 0;
906 gcHeap->markSize = 0;
907#endif
908
909 /* Latch these so that the other calls to dvmHeapScanMarkedObjects() don't
910 * mess with them.
911 */
912 softReferences = gcHeap->softReferences;
913 weakReferences = gcHeap->weakReferences;
914 phantomReferences = gcHeap->phantomReferences;
915
916 /* All strongly-reachable objects have now been marked.
917 */
918 if (gcHeap->softReferenceCollectionState != SR_COLLECT_NONE) {
919 LOGD_HEAP("Handling soft references...");
920 dvmHeapHandleReferences(softReferences, REF_SOFT);
921 // markCount always zero
922
923 /* Now that we've tried collecting SoftReferences,
924 * fall back to not collecting them. If the heap
925 * grows, we will start collecting again.
926 */
927 gcHeap->softReferenceCollectionState = SR_COLLECT_NONE;
928 } // else dvmHeapScanMarkedObjects() already marked the soft-reachable set
929 LOGD_HEAP("Handling weak references...");
930 dvmHeapHandleReferences(weakReferences, REF_WEAK);
931 // markCount always zero
932
933 /* Once all weak-reachable objects have been taken
934 * care of, any remaining unmarked objects can be finalized.
935 */
936 LOGD_HEAP("Finding finalizations...");
937 dvmHeapScheduleFinalizations();
938#if DVM_TRACK_HEAP_MARKING
939 finalizeMarkCount = gcHeap->markCount;
940 finalizeMarkSize = gcHeap->markSize;
941 gcHeap->markCount = 0;
942 gcHeap->markSize = 0;
943#endif
944
945 /* Any remaining objects that are not pending finalization
946 * could be phantom-reachable. This will mark any phantom-reachable
947 * objects, as well as enqueue their references.
948 */
949 LOGD_HEAP("Handling phantom references...");
950 dvmHeapHandleReferences(phantomReferences, REF_PHANTOM);
951#if DVM_TRACK_HEAP_MARKING
952 phantomMarkCount = gcHeap->markCount;
953 phantomMarkSize = gcHeap->markSize;
954 gcHeap->markCount = 0;
955 gcHeap->markSize = 0;
956#endif
957
958//TODO: take care of JNI weak global references
959
960#if DVM_TRACK_HEAP_MARKING
961 LOGI_HEAP("Marked objects: %dB strong, %dB final, %dB phantom\n",
962 strongMarkSize, finalizeMarkSize, phantomMarkSize);
963#endif
964
965#ifdef WITH_DEADLOCK_PREDICTION
966 dvmDumpMonitorInfo("before sweep");
967#endif
968 LOGD_HEAP("Sweeping...");
969 dvmHeapSweepUnmarkedObjects(&numFreed, &sizeFreed);
970#ifdef WITH_DEADLOCK_PREDICTION
971 dvmDumpMonitorInfo("after sweep");
972#endif
973
974 LOGD_HEAP("Cleaning up...");
975 dvmHeapFinishMarkStep();
976
977 LOGD_HEAP("Done.");
978
979 /* Now's a good time to adjust the heap size, since
980 * we know what our utilization is.
981 *
982 * This doesn't actually resize any memory;
983 * it just lets the heap grow more when necessary.
984 */
985 dvmHeapSourceGrowForUtilization();
986 dvmHeapSizeChanged();
987
988#if WITH_HPROF
989 if (gcHeap->hprofContext != NULL) {
990 hprofFinishHeapDump(gcHeap->hprofContext);
991//TODO: write a HEAP_SUMMARY record
Andy McFadden8c880b92009-03-24 18:15:56 -0700992 if (hprofShutdown(gcHeap->hprofContext))
993 gcHeap->hprofResult = 0; /* indicate success */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800994 gcHeap->hprofContext = NULL;
995 }
996#endif
997
998 /* Now that we've freed up the GC heap, return any large
999 * free chunks back to the system. They'll get paged back
1000 * in the next time they're used. Don't do it immediately,
1001 * though; if the process is still allocating a bunch of
1002 * memory, we'll be taking a ton of page faults that we don't
1003 * necessarily need to.
1004 *
1005 * Cancel any old scheduled trims, and schedule a new one.
1006 */
1007 dvmScheduleHeapSourceTrim(5); // in seconds
1008
1009#ifdef WITH_PROFILER
1010 dvmMethodTraceGCEnd();
1011#endif
1012 LOGV_HEAP("GC finished -- resuming threads\n");
1013
1014 gcHeap->gcRunning = false;
1015
1016 dvmUnlockMutex(&gDvm.heapWorkerListLock);
1017 dvmUnlockMutex(&gDvm.heapWorkerLock);
1018
1019 dvmResumeAllThreads(SUSPEND_FOR_GC);
1020 if (oldThreadPriority != kInvalidPriority) {
1021 if (setpriority(PRIO_PROCESS, 0, oldThreadPriority) != 0) {
1022 LOGW_HEAP("Unable to reset priority to %d: %s\n",
1023 oldThreadPriority, strerror(errno));
1024 } else {
1025 LOGD_HEAP("Reset priority to %d\n", oldThreadPriority);
1026 }
San Mehat256fc152009-04-21 14:03:06 -07001027
San Mehat3e371e22009-06-26 08:36:16 -07001028 if (oldThreadPriority >= ANDROID_PRIORITY_BACKGROUND) {
San Mehat256fc152009-04-21 14:03:06 -07001029 dvmChangeThreadSchedulerGroup("bg_non_interactive");
1030 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001031 }
1032 gcElapsedTime = (dvmGetRelativeTimeUsec() - gcHeap->gcStartTime) / 1000;
1033 if (gcElapsedTime < 10000) {
1034 LOGD("GC freed %d objects / %zd bytes in %dms\n",
1035 numFreed, sizeFreed, (int)gcElapsedTime);
1036 } else {
1037 LOGD("GC freed %d objects / %zd bytes in %d sec\n",
1038 numFreed, sizeFreed, (int)(gcElapsedTime / 1000));
1039 }
1040 dvmLogGcStats(numFreed, sizeFreed, gcElapsedTime);
1041
1042 if (gcHeap->ddmHpifWhen != 0) {
1043 LOGD_HEAP("Sending VM heap info to DDM\n");
1044 dvmDdmSendHeapInfo(gcHeap->ddmHpifWhen, false);
1045 }
1046 if (gcHeap->ddmHpsgWhen != 0) {
1047 LOGD_HEAP("Dumping VM heap to DDM\n");
1048 dvmDdmSendHeapSegments(false, false);
1049 }
1050 if (gcHeap->ddmNhsgWhen != 0) {
1051 LOGD_HEAP("Dumping native heap to DDM\n");
1052 dvmDdmSendHeapSegments(false, true);
1053 }
1054}
1055
1056#if WITH_HPROF
1057/*
1058 * Perform garbage collection, writing heap information to the specified file.
1059 *
1060 * If "fileName" is NULL, a suitable name will be generated automatically.
Andy McFadden8c880b92009-03-24 18:15:56 -07001061 *
1062 * Returns 0 on success, or an error code on failure.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001063 */
Andy McFadden8c880b92009-03-24 18:15:56 -07001064int hprofDumpHeap(const char* fileName)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001065{
Andy McFadden8c880b92009-03-24 18:15:56 -07001066 int result;
1067
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001068 dvmLockMutex(&gDvm.gcHeapLock);
1069
1070 gDvm.gcHeap->hprofDumpOnGc = true;
1071 gDvm.gcHeap->hprofFileName = fileName;
1072 dvmCollectGarbageInternal(false);
Andy McFadden8c880b92009-03-24 18:15:56 -07001073 result = gDvm.gcHeap->hprofResult;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001074
1075 dvmUnlockMutex(&gDvm.gcHeapLock);
Andy McFadden8c880b92009-03-24 18:15:56 -07001076
1077 return result;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001078}
1079
1080void dvmHeapSetHprofGcScanState(hprof_heap_tag_t state, u4 threadSerialNumber)
1081{
1082 if (gDvm.gcHeap->hprofContext != NULL) {
1083 hprofSetGcScanState(gDvm.gcHeap->hprofContext, state,
1084 threadSerialNumber);
1085 }
1086}
1087#endif