blob: bc852ca60102d8ef9cf520c185ce56b79ca24951 [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"
Barry Hayes962adba2010-03-17 12:12:39 -070020#include "alloc/HeapBitmap.h"
21#include "alloc/Verify.h"
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080022#include "alloc/HeapTable.h"
23#include "alloc/Heap.h"
24#include "alloc/HeapInternal.h"
25#include "alloc/DdmHeap.h"
26#include "alloc/HeapSource.h"
27#include "alloc/MarkSweep.h"
28
29#include "utils/threads.h" // need Android thread priorities
30#define kInvalidPriority 10000
31
San Mehat5a2056c2009-09-12 10:10:13 -070032#include <cutils/sched_policy.h>
33
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080034#include <sys/time.h>
35#include <sys/resource.h>
36#include <limits.h>
37#include <errno.h>
38
Barry Hayes1b9b4e42010-01-04 10:33:46 -080039static const char* GcReasonStr[] = {
40 [GC_FOR_MALLOC] = "GC_FOR_MALLOC",
41 [GC_EXPLICIT] = "GC_EXPLICIT",
42 [GC_EXTERNAL_ALLOC] = "GC_EXTERNAL_ALLOC",
43 [GC_HPROF_DUMP_HEAP] = "GC_HPROF_DUMP_HEAP"
44};
45
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080046/*
47 * Initialize the GC heap.
48 *
49 * Returns true if successful, false otherwise.
50 */
51bool dvmHeapStartup()
52{
53 GcHeap *gcHeap;
54
55#if defined(WITH_ALLOC_LIMITS)
56 gDvm.checkAllocLimits = false;
57 gDvm.allocationLimit = -1;
58#endif
59
60 gcHeap = dvmHeapSourceStartup(gDvm.heapSizeStart, gDvm.heapSizeMax);
61 if (gcHeap == NULL) {
62 return false;
63 }
64 gcHeap->heapWorkerCurrentObject = NULL;
65 gcHeap->heapWorkerCurrentMethod = NULL;
66 gcHeap->heapWorkerInterpStartTime = 0LL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080067 gcHeap->ddmHpifWhen = 0;
68 gcHeap->ddmHpsgWhen = 0;
69 gcHeap->ddmHpsgWhat = 0;
70 gcHeap->ddmNhsgWhen = 0;
71 gcHeap->ddmNhsgWhat = 0;
72#if WITH_HPROF
73 gcHeap->hprofDumpOnGc = false;
74 gcHeap->hprofContext = NULL;
75#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080076 gDvm.gcHeap = gcHeap;
77
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080078 /* Set up the lists and lock we'll use for finalizable
79 * and reference objects.
80 */
81 dvmInitMutex(&gDvm.heapWorkerListLock);
82 gcHeap->finalizableRefs = NULL;
83 gcHeap->pendingFinalizationRefs = NULL;
84 gcHeap->referenceOperations = NULL;
85
86 /* Initialize the HeapWorker locks and other state
87 * that the GC uses.
88 */
89 dvmInitializeHeapWorkerState();
90
91 return true;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080092}
93
Carl Shapiroc8e06c82010-02-04 19:12:55 -080094void dvmHeapStartupAfterZygote()
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080095{
96 /* Update our idea of the last GC start time so that we
97 * don't use the last time that Zygote happened to GC.
98 */
99 gDvm.gcHeap->gcStartTime = dvmGetRelativeTimeUsec();
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800100}
101
102void dvmHeapShutdown()
103{
104//TODO: make sure we're locked
105 if (gDvm.gcHeap != NULL) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800106 /* Tables are allocated on the native heap;
107 * they need to be cleaned up explicitly.
108 * The process may stick around, so we don't
109 * want to leak any native memory.
110 */
Carl Shapiroa199eb72010-02-09 16:26:30 -0800111 dvmHeapFreeLargeTable(gDvm.gcHeap->finalizableRefs);
112 gDvm.gcHeap->finalizableRefs = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800113
Carl Shapiroa199eb72010-02-09 16:26:30 -0800114 dvmHeapFreeLargeTable(gDvm.gcHeap->pendingFinalizationRefs);
115 gDvm.gcHeap->pendingFinalizationRefs = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800116
Carl Shapiroa199eb72010-02-09 16:26:30 -0800117 dvmHeapFreeLargeTable(gDvm.gcHeap->referenceOperations);
118 gDvm.gcHeap->referenceOperations = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800119
120 /* Destroy the heap. Any outstanding pointers
121 * will point to unmapped memory (unless/until
Carl Shapiroa199eb72010-02-09 16:26:30 -0800122 * someone else maps it). This frees gDvm.gcHeap
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800123 * as a side-effect.
124 */
Carl Shapiroa199eb72010-02-09 16:26:30 -0800125 dvmHeapSourceShutdown(&gDvm.gcHeap);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800126 }
127}
128
129/*
130 * We've been asked to allocate something we can't, e.g. an array so
Andy McFadden6da743b2009-07-15 16:56:00 -0700131 * large that (length * elementWidth) is larger than 2^31.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800132 *
Andy McFadden6da743b2009-07-15 16:56:00 -0700133 * _The Java Programming Language_, 4th edition, says, "you can be sure
134 * that all SoftReferences to softly reachable objects will be cleared
135 * before an OutOfMemoryError is thrown."
136 *
137 * It's unclear whether that holds for all situations where an OOM can
138 * be thrown, or just in the context of an allocation that fails due
139 * to lack of heap space. For simplicity we just throw the exception.
140 *
141 * (OOM due to actually running out of space is handled elsewhere.)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800142 */
143void dvmThrowBadAllocException(const char* msg)
144{
Andy McFadden6da743b2009-07-15 16:56:00 -0700145 dvmThrowException("Ljava/lang/OutOfMemoryError;", msg);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800146}
147
148/*
149 * Grab the lock, but put ourselves into THREAD_VMWAIT if it looks like
150 * we're going to have to wait on the mutex.
151 */
152bool dvmLockHeap()
153{
Carl Shapiro980ffb02010-03-13 22:34:01 -0800154 if (dvmTryLockMutex(&gDvm.gcHeapLock) != 0) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800155 Thread *self;
156 ThreadStatus oldStatus;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800157
158 self = dvmThreadSelf();
159 if (self != NULL) {
160 oldStatus = dvmChangeStatus(self, THREAD_VMWAIT);
161 } else {
The Android Open Source Project99409882009-03-18 22:20:24 -0700162 LOGI("ODD: waiting on heap lock, no self\n");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800163 oldStatus = -1; // shut up gcc
164 }
Carl Shapiro980ffb02010-03-13 22:34:01 -0800165 dvmLockMutex(&gDvm.gcHeapLock);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800166 if (self != NULL) {
167 dvmChangeStatus(self, oldStatus);
168 }
169 }
170
171 return true;
172}
173
174void dvmUnlockHeap()
175{
176 dvmUnlockMutex(&gDvm.gcHeapLock);
177}
178
179/* Pop an object from the list of pending finalizations and
180 * reference clears/enqueues, and return the object.
181 * The caller must call dvmReleaseTrackedAlloc()
182 * on the object when finished.
183 *
184 * Typically only called by the heap worker thread.
185 */
186Object *dvmGetNextHeapWorkerObject(HeapWorkerOperation *op)
187{
188 Object *obj;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800189 GcHeap *gcHeap = gDvm.gcHeap;
190
191 assert(op != NULL);
192
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800193 dvmLockMutex(&gDvm.heapWorkerListLock);
194
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800195 obj = dvmHeapGetNextObjectFromLargeTable(&gcHeap->referenceOperations);
196 if (obj != NULL) {
Carl Shapiro646ba092010-06-10 15:17:00 -0700197 *op = WORKER_ENQUEUE;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800198 } else {
199 obj = dvmHeapGetNextObjectFromLargeTable(
200 &gcHeap->pendingFinalizationRefs);
201 if (obj != NULL) {
202 *op = WORKER_FINALIZE;
203 }
204 }
205
206 if (obj != NULL) {
207 /* Don't let the GC collect the object until the
208 * worker thread is done with it.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800209 */
210 dvmAddTrackedAlloc(obj, NULL);
211 }
212
213 dvmUnlockMutex(&gDvm.heapWorkerListLock);
214
215 return obj;
216}
217
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800218/* Whenever the effective heap size may have changed,
219 * this function must be called.
220 */
221void dvmHeapSizeChanged()
222{
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800223}
224
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800225/* Do a full garbage collection, which may grow the
226 * heap as a side-effect if the live set is large.
227 */
228static void gcForMalloc(bool collectSoftReferences)
229{
230#ifdef WITH_PROFILER
231 if (gDvm.allocProf.enabled) {
232 Thread* self = dvmThreadSelf();
233 gDvm.allocProf.gcCount++;
234 if (self != NULL) {
235 self->allocProf.gcCount++;
236 }
237 }
238#endif
239 /* This may adjust the soft limit as a side-effect.
240 */
241 LOGD_HEAP("dvmMalloc initiating GC%s\n",
242 collectSoftReferences ? "(collect SoftReferences)" : "");
Barry Hayes1b9b4e42010-01-04 10:33:46 -0800243 dvmCollectGarbageInternal(collectSoftReferences, GC_FOR_MALLOC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800244}
245
246/* Try as hard as possible to allocate some memory.
247 */
Carl Shapiro6343bd02010-02-16 17:40:19 -0800248static void *tryMalloc(size_t size)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800249{
Carl Shapiro6343bd02010-02-16 17:40:19 -0800250 void *ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800251
252 /* Don't try too hard if there's no way the allocation is
253 * going to succeed. We have to collect SoftReferences before
254 * throwing an OOME, though.
255 */
256 if (size >= gDvm.heapSizeMax) {
257 LOGW_HEAP("dvmMalloc(%zu/0x%08zx): "
258 "someone's allocating a huge buffer\n", size, size);
Carl Shapiro6343bd02010-02-16 17:40:19 -0800259 ptr = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800260 goto collect_soft_refs;
261 }
262
263//TODO: figure out better heuristics
264// There will be a lot of churn if someone allocates a bunch of
265// big objects in a row, and we hit the frag case each time.
266// A full GC for each.
267// Maybe we grow the heap in bigger leaps
268// Maybe we skip the GC if the size is large and we did one recently
269// (number of allocations ago) (watch for thread effects)
270// DeflateTest allocs a bunch of ~128k buffers w/in 0-5 allocs of each other
271// (or, at least, there are only 0-5 objects swept each time)
272
Carl Shapiro6343bd02010-02-16 17:40:19 -0800273 ptr = dvmHeapSourceAlloc(size);
274 if (ptr != NULL) {
275 return ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800276 }
277
278 /* The allocation failed. Free up some space by doing
279 * a full garbage collection. This may grow the heap
280 * if the live set is sufficiently large.
281 */
282 gcForMalloc(false);
Carl Shapiro6343bd02010-02-16 17:40:19 -0800283 ptr = dvmHeapSourceAlloc(size);
284 if (ptr != NULL) {
285 return ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800286 }
287
288 /* Even that didn't work; this is an exceptional state.
289 * Try harder, growing the heap if necessary.
290 */
Carl Shapiro6343bd02010-02-16 17:40:19 -0800291 ptr = dvmHeapSourceAllocAndGrow(size);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800292 dvmHeapSizeChanged();
Carl Shapiro6343bd02010-02-16 17:40:19 -0800293 if (ptr != NULL) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800294 size_t newHeapSize;
295
296 newHeapSize = dvmHeapSourceGetIdealFootprint();
297//TODO: may want to grow a little bit more so that the amount of free
298// space is equal to the old free space + the utilization slop for
299// the new allocation.
300 LOGI_HEAP("Grow heap (frag case) to "
301 "%zu.%03zuMB for %zu-byte allocation\n",
302 FRACTIONAL_MB(newHeapSize), size);
Carl Shapiro6343bd02010-02-16 17:40:19 -0800303 return ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800304 }
305
306 /* Most allocations should have succeeded by now, so the heap
307 * is really full, really fragmented, or the requested size is
308 * really big. Do another GC, collecting SoftReferences this
309 * time. The VM spec requires that all SoftReferences have
310 * been collected and cleared before throwing an OOME.
311 */
312//TODO: wait for the finalizers from the previous GC to finish
313collect_soft_refs:
314 LOGI_HEAP("Forcing collection of SoftReferences for %zu-byte allocation\n",
315 size);
316 gcForMalloc(true);
Carl Shapiro6343bd02010-02-16 17:40:19 -0800317 ptr = dvmHeapSourceAllocAndGrow(size);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800318 dvmHeapSizeChanged();
Carl Shapiro6343bd02010-02-16 17:40:19 -0800319 if (ptr != NULL) {
320 return ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800321 }
322//TODO: maybe wait for finalizers and try one last time
323
324 LOGE_HEAP("Out of memory on a %zd-byte allocation.\n", size);
325//TODO: tell the HeapSource to dump its state
326 dvmDumpThread(dvmThreadSelf(), false);
327
328 return NULL;
329}
330
331/* Throw an OutOfMemoryError if there's a thread to attach it to.
332 * Avoid recursing.
333 *
334 * The caller must not be holding the heap lock, or else the allocations
335 * in dvmThrowException() will deadlock.
336 */
337static void throwOOME()
338{
339 Thread *self;
340
341 if ((self = dvmThreadSelf()) != NULL) {
342 /* If the current (failing) dvmMalloc() happened as part of thread
343 * creation/attachment before the thread became part of the root set,
344 * we can't rely on the thread-local trackedAlloc table, so
345 * we can't keep track of a real allocated OOME object. But, since
346 * the thread is in the process of being created, it won't have
347 * a useful stack anyway, so we may as well make things easier
348 * by throwing the (stackless) pre-built OOME.
349 */
350 if (dvmIsOnThreadList(self) && !self->throwingOOME) {
351 /* Let ourselves know that we tried to throw an OOM
352 * error in the normal way in case we run out of
353 * memory trying to allocate it inside dvmThrowException().
354 */
355 self->throwingOOME = true;
356
357 /* Don't include a description string;
358 * one fewer allocation.
359 */
360 dvmThrowException("Ljava/lang/OutOfMemoryError;", NULL);
361 } else {
362 /*
363 * This thread has already tried to throw an OutOfMemoryError,
364 * which probably means that we're running out of memory
365 * while recursively trying to throw.
366 *
367 * To avoid any more allocation attempts, "throw" a pre-built
368 * OutOfMemoryError object (which won't have a useful stack trace).
369 *
370 * Note that since this call can't possibly allocate anything,
371 * we don't care about the state of self->throwingOOME
372 * (which will usually already be set).
373 */
374 dvmSetException(self, gDvm.outOfMemoryObj);
375 }
376 /* We're done with the possible recursion.
377 */
378 self->throwingOOME = false;
379 }
380}
381
382/*
383 * Allocate storage on the GC heap. We guarantee 8-byte alignment.
384 *
385 * The new storage is zeroed out.
386 *
387 * Note that, in rare cases, this could get called while a GC is in
388 * progress. If a non-VM thread tries to attach itself through JNI,
389 * it will need to allocate some objects. If this becomes annoying to
390 * deal with, we can block it at the source, but holding the allocation
391 * mutex should be enough.
392 *
393 * In rare circumstances (JNI AttachCurrentThread) we can be called
394 * from a non-VM thread.
395 *
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800396 * Use ALLOC_DONT_TRACK when we either don't want to track an allocation
397 * (because it's being done for the interpreter "new" operation and will
398 * be part of the root set immediately) or we can't (because this allocation
399 * is for a brand new thread).
400 *
401 * Returns NULL and throws an exception on failure.
402 *
403 * TODO: don't do a GC if the debugger thinks all threads are suspended
404 */
405void* dvmMalloc(size_t size, int flags)
406{
407 GcHeap *gcHeap = gDvm.gcHeap;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800408 void *ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800409
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800410#if defined(WITH_ALLOC_LIMITS)
411 /*
412 * See if they've exceeded the allocation limit for this thread.
413 *
414 * A limit value of -1 means "no limit".
415 *
416 * This is enabled at compile time because it requires us to do a
417 * TLS lookup for the Thread pointer. This has enough of a performance
418 * impact that we don't want to do it if we don't have to. (Now that
419 * we're using gDvm.checkAllocLimits we may want to reconsider this,
420 * but it's probably still best to just compile the check out of
421 * production code -- one less thing to hit on every allocation.)
422 */
423 if (gDvm.checkAllocLimits) {
424 Thread* self = dvmThreadSelf();
425 if (self != NULL) {
426 int count = self->allocLimit;
427 if (count > 0) {
428 self->allocLimit--;
429 } else if (count == 0) {
430 /* fail! */
431 assert(!gDvm.initializing);
432 self->allocLimit = -1;
433 dvmThrowException("Ldalvik/system/AllocationLimitError;",
434 "thread allocation limit exceeded");
435 return NULL;
436 }
437 }
438 }
439
440 if (gDvm.allocationLimit >= 0) {
441 assert(!gDvm.initializing);
442 gDvm.allocationLimit = -1;
443 dvmThrowException("Ldalvik/system/AllocationLimitError;",
444 "global allocation limit exceeded");
445 return NULL;
446 }
447#endif
448
449 dvmLockHeap();
450
451 /* Try as hard as possible to allocate some memory.
452 */
Carl Shapiro6343bd02010-02-16 17:40:19 -0800453 ptr = tryMalloc(size);
454 if (ptr != NULL) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800455 /* We've got the memory.
456 */
457 if ((flags & ALLOC_FINALIZABLE) != 0) {
458 /* This object is an instance of a class that
459 * overrides finalize(). Add it to the finalizable list.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800460 */
461 if (!dvmHeapAddRefToLargeTable(&gcHeap->finalizableRefs,
Carl Shapiro6343bd02010-02-16 17:40:19 -0800462 (Object *)ptr))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800463 {
464 LOGE_HEAP("dvmMalloc(): no room for any more "
465 "finalizable objects\n");
466 dvmAbort();
467 }
468 }
469
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800470#ifdef WITH_PROFILER
471 if (gDvm.allocProf.enabled) {
472 Thread* self = dvmThreadSelf();
473 gDvm.allocProf.allocCount++;
474 gDvm.allocProf.allocSize += size;
475 if (self != NULL) {
476 self->allocProf.allocCount++;
477 self->allocProf.allocSize += size;
478 }
479 }
480#endif
481 } else {
482 /* The allocation failed.
483 */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800484
485#ifdef WITH_PROFILER
486 if (gDvm.allocProf.enabled) {
487 Thread* self = dvmThreadSelf();
488 gDvm.allocProf.failedAllocCount++;
489 gDvm.allocProf.failedAllocSize += size;
490 if (self != NULL) {
491 self->allocProf.failedAllocCount++;
492 self->allocProf.failedAllocSize += size;
493 }
494 }
495#endif
496 }
497
498 dvmUnlockHeap();
499
500 if (ptr != NULL) {
501 /*
Barry Hayesd4f78d32010-06-08 09:34:42 -0700502 * If caller hasn't asked us not to track it, add it to the
503 * internal tracking list.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800504 */
Barry Hayesd4f78d32010-06-08 09:34:42 -0700505 if ((flags & ALLOC_DONT_TRACK) == 0) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800506 dvmAddTrackedAlloc(ptr, NULL);
507 }
508 } else {
Ben Chengc3b92b22010-01-26 16:46:15 -0800509 /*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800510 * The allocation failed; throw an OutOfMemoryError.
511 */
512 throwOOME();
513 }
514
515 return ptr;
516}
517
518/*
519 * Returns true iff <obj> points to a valid allocated object.
520 */
521bool dvmIsValidObject(const Object* obj)
522{
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800523 /* Don't bother if it's NULL or not 8-byte aligned.
524 */
Carl Shapiro6343bd02010-02-16 17:40:19 -0800525 if (obj != NULL && ((uintptr_t)obj & (8-1)) == 0) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800526 /* Even if the heap isn't locked, this shouldn't return
527 * any false negatives. The only mutation that could
528 * be happening is allocation, which means that another
529 * thread could be in the middle of a read-modify-write
530 * to add a new bit for a new object. However, that
531 * RMW will have completed by the time any other thread
532 * could possibly see the new pointer, so there is no
533 * danger of dvmIsValidObject() being called on a valid
534 * pointer whose bit isn't set.
535 *
536 * Freeing will only happen during the sweep phase, which
537 * only happens while the heap is locked.
538 */
Carl Shapiro6343bd02010-02-16 17:40:19 -0800539 return dvmHeapSourceContains(obj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800540 }
541 return false;
542}
543
Barry Hayes364f9d92010-06-11 16:12:47 -0700544/*
545 * Returns true iff <obj> points to a word-aligned address within Heap
546 * address space.
547 */
548bool dvmIsValidObjectAddress(const void* ptr)
549{
550 /* Don't bother if it's not 4-byte aligned.
551 */
552 if (((uintptr_t)ptr & (4-1)) == 0) {
553 return dvmHeapSourceContainsAddress(ptr);
554 }
555 return false;
556}
557
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800558size_t dvmObjectSizeInHeap(const Object *obj)
559{
Carl Shapiro6343bd02010-02-16 17:40:19 -0800560 return dvmHeapSourceChunkSize(obj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800561}
562
563/*
Barry Hayes962adba2010-03-17 12:12:39 -0700564 * Scan every live object in the heap, holding the locks.
565 */
566static void verifyHeap()
567{
568 // TODO: check the locks.
569 HeapBitmap *liveBits = dvmHeapSourceGetLiveBits();
570 dvmVerifyBitmap(liveBits);
571}
572
573/*
574 * Suspend the VM as for a GC, and assert-fail if any object has any
575 * corrupt references.
576 */
577void dvmHeapSuspendAndVerify()
578{
579 /* Suspend the VM. */
580 dvmSuspendAllThreads(SUSPEND_FOR_VERIFY);
581 dvmLockMutex(&gDvm.heapWorkerLock);
582 dvmAssertHeapWorkerThreadRunning();
583 dvmLockMutex(&gDvm.heapWorkerListLock);
584
585 verifyHeap();
586
587 /* Resume the VM. */
588 dvmUnlockMutex(&gDvm.heapWorkerListLock);
589 dvmUnlockMutex(&gDvm.heapWorkerLock);
590 dvmResumeAllThreads(SUSPEND_FOR_VERIFY);
591}
592
593/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800594 * Initiate garbage collection.
595 *
596 * NOTES:
597 * - If we don't hold gDvm.threadListLock, it's possible for a thread to
598 * be added to the thread list while we work. The thread should NOT
599 * start executing, so this is only interesting when we start chasing
600 * thread stacks. (Before we do so, grab the lock.)
601 *
602 * We are not allowed to GC when the debugger has suspended the VM, which
603 * is awkward because debugger requests can cause allocations. The easiest
604 * way to enforce this is to refuse to GC on an allocation made by the
605 * JDWP thread -- we have to expand the heap or fail.
606 */
Carl Shapiro29540742010-03-26 15:34:39 -0700607void dvmCollectGarbageInternal(bool clearSoftRefs, GcReason reason)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800608{
609 GcHeap *gcHeap = gDvm.gcHeap;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800610 u8 now;
611 s8 timeSinceLastGc;
612 s8 gcElapsedTime;
613 int numFreed;
614 size_t sizeFreed;
Carl Shapirod25566d2010-03-11 20:39:47 -0800615 GcMode gcMode;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800616
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800617 /* The heap lock must be held.
618 */
619
620 if (gcHeap->gcRunning) {
621 LOGW_HEAP("Attempted recursive GC\n");
622 return;
623 }
Carl Shapirod25566d2010-03-11 20:39:47 -0800624 gcMode = (reason == GC_FOR_MALLOC) ? GC_PARTIAL : GC_FULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800625 gcHeap->gcRunning = true;
626 now = dvmGetRelativeTimeUsec();
627 if (gcHeap->gcStartTime != 0) {
628 timeSinceLastGc = (now - gcHeap->gcStartTime) / 1000;
629 } else {
630 timeSinceLastGc = 0;
631 }
632 gcHeap->gcStartTime = now;
633
Barry Hayes1b9b4e42010-01-04 10:33:46 -0800634 LOGV_HEAP("%s starting -- suspending threads\n", GcReasonStr[reason]);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800635
636 dvmSuspendAllThreads(SUSPEND_FOR_GC);
637
638 /* Get the priority (the "nice" value) of the current thread. The
639 * getpriority() call can legitimately return -1, so we have to
640 * explicitly test errno.
641 */
642 errno = 0;
643 int oldThreadPriority = kInvalidPriority;
644 int priorityResult = getpriority(PRIO_PROCESS, 0);
645 if (errno != 0) {
646 LOGI_HEAP("getpriority(self) failed: %s\n", strerror(errno));
647 } else if (priorityResult > ANDROID_PRIORITY_NORMAL) {
648 /* Current value is numerically greater than "normal", which
649 * in backward UNIX terms means lower priority.
650 */
San Mehat256fc152009-04-21 14:03:06 -0700651
San Mehat3e371e22009-06-26 08:36:16 -0700652 if (priorityResult >= ANDROID_PRIORITY_BACKGROUND) {
San Mehat5a2056c2009-09-12 10:10:13 -0700653 set_sched_policy(dvmGetSysThreadId(), SP_FOREGROUND);
San Mehat256fc152009-04-21 14:03:06 -0700654 }
655
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800656 if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL) != 0) {
657 LOGI_HEAP("Unable to elevate priority from %d to %d\n",
658 priorityResult, ANDROID_PRIORITY_NORMAL);
659 } else {
660 /* priority elevated; save value so we can restore it later */
661 LOGD_HEAP("Elevating priority from %d to %d\n",
662 priorityResult, ANDROID_PRIORITY_NORMAL);
663 oldThreadPriority = priorityResult;
664 }
665 }
666
667 /* Wait for the HeapWorker thread to block.
668 * (It may also already be suspended in interp code,
669 * in which case it's not holding heapWorkerLock.)
670 */
671 dvmLockMutex(&gDvm.heapWorkerLock);
672
673 /* Make sure that the HeapWorker thread hasn't become
674 * wedged inside interp code. If it has, this call will
675 * print a message and abort the VM.
676 */
677 dvmAssertHeapWorkerThreadRunning();
678
679 /* Lock the pendingFinalizationRefs list.
680 *
681 * Acquire the lock after suspending so the finalizer
682 * thread can't block in the RUNNING state while
683 * we try to suspend.
684 */
685 dvmLockMutex(&gDvm.heapWorkerListLock);
686
Barry Hayes962adba2010-03-17 12:12:39 -0700687 if (gDvm.preVerify) {
688 LOGV_HEAP("Verifying heap before GC");
689 verifyHeap();
690 }
691
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800692#ifdef WITH_PROFILER
693 dvmMethodTraceGCBegin();
694#endif
695
696#if WITH_HPROF
697
698/* Set DUMP_HEAP_ON_DDMS_UPDATE to 1 to enable heap dumps
699 * whenever DDMS requests a heap update (HPIF chunk).
700 * The output files will appear in /data/misc, which must
701 * already exist.
702 * You must define "WITH_HPROF := true" in your buildspec.mk
703 * and recompile libdvm for this to work.
704 *
705 * To enable stack traces for each allocation, define
706 * "WITH_HPROF_STACK := true" in buildspec.mk. This option slows down
707 * allocations and also requires 8 additional bytes per object on the
708 * GC heap.
709 */
710#define DUMP_HEAP_ON_DDMS_UPDATE 0
711#if DUMP_HEAP_ON_DDMS_UPDATE
712 gcHeap->hprofDumpOnGc |= (gcHeap->ddmHpifWhen != 0);
713#endif
714
715 if (gcHeap->hprofDumpOnGc) {
716 char nameBuf[128];
717
The Android Open Source Project99409882009-03-18 22:20:24 -0700718 gcHeap->hprofResult = -1;
719
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800720 if (gcHeap->hprofFileName == NULL) {
721 /* no filename was provided; invent one */
722 sprintf(nameBuf, "/data/misc/heap-dump-tm%d-pid%d.hprof",
723 (int) time(NULL), (int) getpid());
724 gcHeap->hprofFileName = nameBuf;
725 }
Andy McFadden6bf992c2010-01-28 17:01:39 -0800726 gcHeap->hprofContext = hprofStartup(gcHeap->hprofFileName,
727 gcHeap->hprofDirectToDdms);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800728 if (gcHeap->hprofContext != NULL) {
729 hprofStartHeapDump(gcHeap->hprofContext);
730 }
731 gcHeap->hprofDumpOnGc = false;
732 gcHeap->hprofFileName = NULL;
733 }
734#endif
735
736 if (timeSinceLastGc < 10000) {
737 LOGD_HEAP("GC! (%dms since last GC)\n",
738 (int)timeSinceLastGc);
739 } else {
740 LOGD_HEAP("GC! (%d sec since last GC)\n",
741 (int)(timeSinceLastGc / 1000));
742 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800743
744 /* Set up the marking context.
745 */
Carl Shapirod25566d2010-03-11 20:39:47 -0800746 if (!dvmHeapBeginMarkStep(gcMode)) {
The Android Open Source Project99409882009-03-18 22:20:24 -0700747 LOGE_HEAP("dvmHeapBeginMarkStep failed; aborting\n");
748 dvmAbort();
749 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800750
751 /* Mark the set of objects that are strongly reachable from the roots.
752 */
753 LOGD_HEAP("Marking...");
754 dvmHeapMarkRootSet();
755
756 /* dvmHeapScanMarkedObjects() will build the lists of known
757 * instances of the Reference classes.
758 */
759 gcHeap->softReferences = NULL;
760 gcHeap->weakReferences = NULL;
761 gcHeap->phantomReferences = NULL;
762
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800763 /* Recursively mark any objects that marked objects point to strongly.
764 * If we're not collecting soft references, soft-reachable
765 * objects will also be marked.
766 */
767 LOGD_HEAP("Recursing...");
768 dvmHeapScanMarkedObjects();
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800769
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800770 /* All strongly-reachable objects have now been marked.
771 */
Carl Shapiro29540742010-03-26 15:34:39 -0700772 LOGD_HEAP("Handling soft references...");
773 if (!clearSoftRefs) {
774 dvmHandleSoftRefs(&gcHeap->softReferences);
775 }
776 dvmClearWhiteRefs(&gcHeap->softReferences);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800777
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800778 LOGD_HEAP("Handling weak references...");
Carl Shapiro29540742010-03-26 15:34:39 -0700779 dvmClearWhiteRefs(&gcHeap->weakReferences);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800780
781 /* Once all weak-reachable objects have been taken
782 * care of, any remaining unmarked objects can be finalized.
783 */
784 LOGD_HEAP("Finding finalizations...");
785 dvmHeapScheduleFinalizations();
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800786
Carl Shapiro29540742010-03-26 15:34:39 -0700787 LOGD_HEAP("Handling f-reachable soft references...");
788 dvmClearWhiteRefs(&gcHeap->softReferences);
789
790 LOGD_HEAP("Handling f-reachable weak references...");
791 dvmClearWhiteRefs(&gcHeap->weakReferences);
792
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800793 /* Any remaining objects that are not pending finalization
794 * could be phantom-reachable. This will mark any phantom-reachable
795 * objects, as well as enqueue their references.
796 */
797 LOGD_HEAP("Handling phantom references...");
Carl Shapiro29540742010-03-26 15:34:39 -0700798 dvmClearWhiteRefs(&gcHeap->phantomReferences);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800799
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800800#ifdef WITH_DEADLOCK_PREDICTION
801 dvmDumpMonitorInfo("before sweep");
802#endif
803 LOGD_HEAP("Sweeping...");
Carl Shapirod25566d2010-03-11 20:39:47 -0800804 dvmHeapSweepUnmarkedObjects(gcMode, &numFreed, &sizeFreed);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800805#ifdef WITH_DEADLOCK_PREDICTION
806 dvmDumpMonitorInfo("after sweep");
807#endif
808
809 LOGD_HEAP("Cleaning up...");
810 dvmHeapFinishMarkStep();
811
812 LOGD_HEAP("Done.");
813
814 /* Now's a good time to adjust the heap size, since
815 * we know what our utilization is.
816 *
817 * This doesn't actually resize any memory;
818 * it just lets the heap grow more when necessary.
819 */
820 dvmHeapSourceGrowForUtilization();
821 dvmHeapSizeChanged();
822
823#if WITH_HPROF
824 if (gcHeap->hprofContext != NULL) {
825 hprofFinishHeapDump(gcHeap->hprofContext);
826//TODO: write a HEAP_SUMMARY record
The Android Open Source Project99409882009-03-18 22:20:24 -0700827 if (hprofShutdown(gcHeap->hprofContext))
828 gcHeap->hprofResult = 0; /* indicate success */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800829 gcHeap->hprofContext = NULL;
830 }
831#endif
832
833 /* Now that we've freed up the GC heap, return any large
834 * free chunks back to the system. They'll get paged back
835 * in the next time they're used. Don't do it immediately,
836 * though; if the process is still allocating a bunch of
837 * memory, we'll be taking a ton of page faults that we don't
838 * necessarily need to.
839 *
840 * Cancel any old scheduled trims, and schedule a new one.
841 */
842 dvmScheduleHeapSourceTrim(5); // in seconds
843
844#ifdef WITH_PROFILER
845 dvmMethodTraceGCEnd();
846#endif
Barry Hayes962adba2010-03-17 12:12:39 -0700847 LOGV_HEAP("GC finished");
848
849 if (gDvm.postVerify) {
850 LOGV_HEAP("Verifying heap after GC");
851 verifyHeap();
852 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800853
854 gcHeap->gcRunning = false;
855
Barry Hayes962adba2010-03-17 12:12:39 -0700856 LOGV_HEAP("Resuming threads");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800857 dvmUnlockMutex(&gDvm.heapWorkerListLock);
858 dvmUnlockMutex(&gDvm.heapWorkerLock);
859
Ben Chengc3b92b22010-01-26 16:46:15 -0800860#if defined(WITH_JIT)
Ben Chengc3b92b22010-01-26 16:46:15 -0800861 /*
862 * Patching a chaining cell is very cheap as it only updates 4 words. It's
863 * the overhead of stopping all threads and synchronizing the I/D cache
864 * that makes it expensive.
865 *
866 * Therefore we batch those work orders in a queue and go through them
867 * when threads are suspended for GC.
868 */
869 dvmCompilerPerformSafePointChecks();
870#endif
871
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800872 dvmResumeAllThreads(SUSPEND_FOR_GC);
873 if (oldThreadPriority != kInvalidPriority) {
874 if (setpriority(PRIO_PROCESS, 0, oldThreadPriority) != 0) {
875 LOGW_HEAP("Unable to reset priority to %d: %s\n",
876 oldThreadPriority, strerror(errno));
877 } else {
878 LOGD_HEAP("Reset priority to %d\n", oldThreadPriority);
879 }
San Mehat256fc152009-04-21 14:03:06 -0700880
San Mehat3e371e22009-06-26 08:36:16 -0700881 if (oldThreadPriority >= ANDROID_PRIORITY_BACKGROUND) {
San Mehat5a2056c2009-09-12 10:10:13 -0700882 set_sched_policy(dvmGetSysThreadId(), SP_BACKGROUND);
San Mehat256fc152009-04-21 14:03:06 -0700883 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800884 }
885 gcElapsedTime = (dvmGetRelativeTimeUsec() - gcHeap->gcStartTime) / 1000;
Barry Hayes31364132010-01-04 16:10:09 -0800886 LOGD("%s freed %d objects / %zd bytes in %dms\n",
887 GcReasonStr[reason], numFreed, sizeFreed, (int)gcElapsedTime);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800888 dvmLogGcStats(numFreed, sizeFreed, gcElapsedTime);
889
890 if (gcHeap->ddmHpifWhen != 0) {
891 LOGD_HEAP("Sending VM heap info to DDM\n");
892 dvmDdmSendHeapInfo(gcHeap->ddmHpifWhen, false);
893 }
894 if (gcHeap->ddmHpsgWhen != 0) {
895 LOGD_HEAP("Dumping VM heap to DDM\n");
896 dvmDdmSendHeapSegments(false, false);
897 }
898 if (gcHeap->ddmNhsgWhen != 0) {
899 LOGD_HEAP("Dumping native heap to DDM\n");
900 dvmDdmSendHeapSegments(false, true);
901 }
902}
903
904#if WITH_HPROF
905/*
906 * Perform garbage collection, writing heap information to the specified file.
907 *
908 * If "fileName" is NULL, a suitable name will be generated automatically.
The Android Open Source Project99409882009-03-18 22:20:24 -0700909 *
910 * Returns 0 on success, or an error code on failure.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800911 */
Andy McFadden6bf992c2010-01-28 17:01:39 -0800912int hprofDumpHeap(const char* fileName, bool directToDdms)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800913{
The Android Open Source Project99409882009-03-18 22:20:24 -0700914 int result;
915
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800916 dvmLockMutex(&gDvm.gcHeapLock);
917
918 gDvm.gcHeap->hprofDumpOnGc = true;
919 gDvm.gcHeap->hprofFileName = fileName;
Andy McFadden6bf992c2010-01-28 17:01:39 -0800920 gDvm.gcHeap->hprofDirectToDdms = directToDdms;
Barry Hayes1b9b4e42010-01-04 10:33:46 -0800921 dvmCollectGarbageInternal(false, GC_HPROF_DUMP_HEAP);
The Android Open Source Project99409882009-03-18 22:20:24 -0700922 result = gDvm.gcHeap->hprofResult;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800923
924 dvmUnlockMutex(&gDvm.gcHeapLock);
The Android Open Source Project99409882009-03-18 22:20:24 -0700925
926 return result;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800927}
928
929void dvmHeapSetHprofGcScanState(hprof_heap_tag_t state, u4 threadSerialNumber)
930{
931 if (gDvm.gcHeap->hprofContext != NULL) {
932 hprofSetGcScanState(gDvm.gcHeap->hprofContext, state,
933 threadSerialNumber);
934 }
935}
936#endif