blob: ecd7cc8a1f775e712b331033abf9ace03e5eae9d [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",
Carl Shapiroec805ea2010-06-28 16:28:26 -070041 [GC_CONCURRENT] = "GC_CONCURRENT",
Barry Hayes1b9b4e42010-01-04 10:33:46 -080042 [GC_EXPLICIT] = "GC_EXPLICIT",
43 [GC_EXTERNAL_ALLOC] = "GC_EXTERNAL_ALLOC",
44 [GC_HPROF_DUMP_HEAP] = "GC_HPROF_DUMP_HEAP"
45};
46
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080047/*
48 * Initialize the GC heap.
49 *
50 * Returns true if successful, false otherwise.
51 */
52bool dvmHeapStartup()
53{
54 GcHeap *gcHeap;
55
56#if defined(WITH_ALLOC_LIMITS)
57 gDvm.checkAllocLimits = false;
58 gDvm.allocationLimit = -1;
59#endif
60
61 gcHeap = dvmHeapSourceStartup(gDvm.heapSizeStart, gDvm.heapSizeMax);
62 if (gcHeap == NULL) {
63 return false;
64 }
65 gcHeap->heapWorkerCurrentObject = NULL;
66 gcHeap->heapWorkerCurrentMethod = NULL;
67 gcHeap->heapWorkerInterpStartTime = 0LL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080068 gcHeap->ddmHpifWhen = 0;
69 gcHeap->ddmHpsgWhen = 0;
70 gcHeap->ddmHpsgWhat = 0;
71 gcHeap->ddmNhsgWhen = 0;
72 gcHeap->ddmNhsgWhat = 0;
73#if WITH_HPROF
74 gcHeap->hprofDumpOnGc = false;
75 gcHeap->hprofContext = NULL;
76#endif
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080077 gDvm.gcHeap = gcHeap;
78
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080079 /* Set up the lists and lock we'll use for finalizable
80 * and reference objects.
81 */
82 dvmInitMutex(&gDvm.heapWorkerListLock);
83 gcHeap->finalizableRefs = NULL;
84 gcHeap->pendingFinalizationRefs = NULL;
85 gcHeap->referenceOperations = NULL;
86
87 /* Initialize the HeapWorker locks and other state
88 * that the GC uses.
89 */
90 dvmInitializeHeapWorkerState();
91
92 return true;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080093}
94
Carl Shapiroec805ea2010-06-28 16:28:26 -070095bool dvmHeapStartupAfterZygote(void)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080096{
97 /* Update our idea of the last GC start time so that we
98 * don't use the last time that Zygote happened to GC.
99 */
100 gDvm.gcHeap->gcStartTime = dvmGetRelativeTimeUsec();
Carl Shapiroec805ea2010-06-28 16:28:26 -0700101 return dvmHeapSourceStartupAfterZygote();
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800102}
103
104void dvmHeapShutdown()
105{
106//TODO: make sure we're locked
107 if (gDvm.gcHeap != NULL) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800108 /* Tables are allocated on the native heap;
109 * they need to be cleaned up explicitly.
110 * The process may stick around, so we don't
111 * want to leak any native memory.
112 */
Carl Shapiroa199eb72010-02-09 16:26:30 -0800113 dvmHeapFreeLargeTable(gDvm.gcHeap->finalizableRefs);
114 gDvm.gcHeap->finalizableRefs = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800115
Carl Shapiroa199eb72010-02-09 16:26:30 -0800116 dvmHeapFreeLargeTable(gDvm.gcHeap->pendingFinalizationRefs);
117 gDvm.gcHeap->pendingFinalizationRefs = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800118
Carl Shapiroa199eb72010-02-09 16:26:30 -0800119 dvmHeapFreeLargeTable(gDvm.gcHeap->referenceOperations);
120 gDvm.gcHeap->referenceOperations = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800121
122 /* Destroy the heap. Any outstanding pointers
123 * will point to unmapped memory (unless/until
Carl Shapiroa199eb72010-02-09 16:26:30 -0800124 * someone else maps it). This frees gDvm.gcHeap
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800125 * as a side-effect.
126 */
Carl Shapiroa199eb72010-02-09 16:26:30 -0800127 dvmHeapSourceShutdown(&gDvm.gcHeap);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800128 }
129}
130
131/*
Carl Shapiroec805ea2010-06-28 16:28:26 -0700132 * Shutdown any threads internal to the heap.
133 */
134void dvmHeapThreadShutdown(void)
135{
136 dvmHeapSourceThreadShutdown();
137}
138
139/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800140 * We've been asked to allocate something we can't, e.g. an array so
Andy McFadden6da743b2009-07-15 16:56:00 -0700141 * large that (length * elementWidth) is larger than 2^31.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800142 *
Andy McFadden6da743b2009-07-15 16:56:00 -0700143 * _The Java Programming Language_, 4th edition, says, "you can be sure
144 * that all SoftReferences to softly reachable objects will be cleared
145 * before an OutOfMemoryError is thrown."
146 *
147 * It's unclear whether that holds for all situations where an OOM can
148 * be thrown, or just in the context of an allocation that fails due
149 * to lack of heap space. For simplicity we just throw the exception.
150 *
151 * (OOM due to actually running out of space is handled elsewhere.)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800152 */
153void dvmThrowBadAllocException(const char* msg)
154{
Andy McFadden6da743b2009-07-15 16:56:00 -0700155 dvmThrowException("Ljava/lang/OutOfMemoryError;", msg);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800156}
157
158/*
159 * Grab the lock, but put ourselves into THREAD_VMWAIT if it looks like
160 * we're going to have to wait on the mutex.
161 */
162bool dvmLockHeap()
163{
Carl Shapiro980ffb02010-03-13 22:34:01 -0800164 if (dvmTryLockMutex(&gDvm.gcHeapLock) != 0) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800165 Thread *self;
166 ThreadStatus oldStatus;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800167
168 self = dvmThreadSelf();
169 if (self != NULL) {
170 oldStatus = dvmChangeStatus(self, THREAD_VMWAIT);
171 } else {
The Android Open Source Project99409882009-03-18 22:20:24 -0700172 LOGI("ODD: waiting on heap lock, no self\n");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800173 oldStatus = -1; // shut up gcc
174 }
Carl Shapiro980ffb02010-03-13 22:34:01 -0800175 dvmLockMutex(&gDvm.gcHeapLock);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800176 if (self != NULL) {
177 dvmChangeStatus(self, oldStatus);
178 }
179 }
180
181 return true;
182}
183
184void dvmUnlockHeap()
185{
186 dvmUnlockMutex(&gDvm.gcHeapLock);
187}
188
189/* Pop an object from the list of pending finalizations and
190 * reference clears/enqueues, and return the object.
191 * The caller must call dvmReleaseTrackedAlloc()
192 * on the object when finished.
193 *
194 * Typically only called by the heap worker thread.
195 */
196Object *dvmGetNextHeapWorkerObject(HeapWorkerOperation *op)
197{
198 Object *obj;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800199 GcHeap *gcHeap = gDvm.gcHeap;
200
201 assert(op != NULL);
202
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800203 dvmLockMutex(&gDvm.heapWorkerListLock);
204
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800205 obj = dvmHeapGetNextObjectFromLargeTable(&gcHeap->referenceOperations);
206 if (obj != NULL) {
Carl Shapiro646ba092010-06-10 15:17:00 -0700207 *op = WORKER_ENQUEUE;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800208 } else {
209 obj = dvmHeapGetNextObjectFromLargeTable(
210 &gcHeap->pendingFinalizationRefs);
211 if (obj != NULL) {
212 *op = WORKER_FINALIZE;
213 }
214 }
215
216 if (obj != NULL) {
217 /* Don't let the GC collect the object until the
218 * worker thread is done with it.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800219 */
220 dvmAddTrackedAlloc(obj, NULL);
221 }
222
223 dvmUnlockMutex(&gDvm.heapWorkerListLock);
224
225 return obj;
226}
227
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800228/* Whenever the effective heap size may have changed,
229 * this function must be called.
230 */
231void dvmHeapSizeChanged()
232{
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800233}
234
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800235/* Do a full garbage collection, which may grow the
236 * heap as a side-effect if the live set is large.
237 */
238static void gcForMalloc(bool collectSoftReferences)
239{
240#ifdef WITH_PROFILER
241 if (gDvm.allocProf.enabled) {
242 Thread* self = dvmThreadSelf();
243 gDvm.allocProf.gcCount++;
244 if (self != NULL) {
245 self->allocProf.gcCount++;
246 }
247 }
248#endif
249 /* This may adjust the soft limit as a side-effect.
250 */
251 LOGD_HEAP("dvmMalloc initiating GC%s\n",
252 collectSoftReferences ? "(collect SoftReferences)" : "");
Barry Hayes1b9b4e42010-01-04 10:33:46 -0800253 dvmCollectGarbageInternal(collectSoftReferences, GC_FOR_MALLOC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800254}
255
256/* Try as hard as possible to allocate some memory.
257 */
Carl Shapiro6343bd02010-02-16 17:40:19 -0800258static void *tryMalloc(size_t size)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800259{
Carl Shapiro6343bd02010-02-16 17:40:19 -0800260 void *ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800261
262 /* Don't try too hard if there's no way the allocation is
263 * going to succeed. We have to collect SoftReferences before
264 * throwing an OOME, though.
265 */
266 if (size >= gDvm.heapSizeMax) {
267 LOGW_HEAP("dvmMalloc(%zu/0x%08zx): "
268 "someone's allocating a huge buffer\n", size, size);
Carl Shapiro6343bd02010-02-16 17:40:19 -0800269 ptr = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800270 goto collect_soft_refs;
271 }
272
273//TODO: figure out better heuristics
274// There will be a lot of churn if someone allocates a bunch of
275// big objects in a row, and we hit the frag case each time.
276// A full GC for each.
277// Maybe we grow the heap in bigger leaps
278// Maybe we skip the GC if the size is large and we did one recently
279// (number of allocations ago) (watch for thread effects)
280// DeflateTest allocs a bunch of ~128k buffers w/in 0-5 allocs of each other
281// (or, at least, there are only 0-5 objects swept each time)
282
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 /* The allocation failed. Free up some space by doing
289 * a full garbage collection. This may grow the heap
290 * if the live set is sufficiently large.
291 */
292 gcForMalloc(false);
Carl Shapiro6343bd02010-02-16 17:40:19 -0800293 ptr = dvmHeapSourceAlloc(size);
294 if (ptr != NULL) {
295 return ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800296 }
297
298 /* Even that didn't work; this is an exceptional state.
299 * Try harder, growing the heap if necessary.
300 */
Carl Shapiro6343bd02010-02-16 17:40:19 -0800301 ptr = dvmHeapSourceAllocAndGrow(size);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800302 dvmHeapSizeChanged();
Carl Shapiro6343bd02010-02-16 17:40:19 -0800303 if (ptr != NULL) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800304 size_t newHeapSize;
305
306 newHeapSize = dvmHeapSourceGetIdealFootprint();
307//TODO: may want to grow a little bit more so that the amount of free
308// space is equal to the old free space + the utilization slop for
309// the new allocation.
310 LOGI_HEAP("Grow heap (frag case) to "
311 "%zu.%03zuMB for %zu-byte allocation\n",
312 FRACTIONAL_MB(newHeapSize), size);
Carl Shapiro6343bd02010-02-16 17:40:19 -0800313 return ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800314 }
315
316 /* Most allocations should have succeeded by now, so the heap
317 * is really full, really fragmented, or the requested size is
318 * really big. Do another GC, collecting SoftReferences this
319 * time. The VM spec requires that all SoftReferences have
320 * been collected and cleared before throwing an OOME.
321 */
322//TODO: wait for the finalizers from the previous GC to finish
323collect_soft_refs:
324 LOGI_HEAP("Forcing collection of SoftReferences for %zu-byte allocation\n",
325 size);
326 gcForMalloc(true);
Carl Shapiro6343bd02010-02-16 17:40:19 -0800327 ptr = dvmHeapSourceAllocAndGrow(size);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800328 dvmHeapSizeChanged();
Carl Shapiro6343bd02010-02-16 17:40:19 -0800329 if (ptr != NULL) {
330 return ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800331 }
332//TODO: maybe wait for finalizers and try one last time
333
334 LOGE_HEAP("Out of memory on a %zd-byte allocation.\n", size);
335//TODO: tell the HeapSource to dump its state
336 dvmDumpThread(dvmThreadSelf(), false);
337
338 return NULL;
339}
340
341/* Throw an OutOfMemoryError if there's a thread to attach it to.
342 * Avoid recursing.
343 *
344 * The caller must not be holding the heap lock, or else the allocations
345 * in dvmThrowException() will deadlock.
346 */
347static void throwOOME()
348{
349 Thread *self;
350
351 if ((self = dvmThreadSelf()) != NULL) {
352 /* If the current (failing) dvmMalloc() happened as part of thread
353 * creation/attachment before the thread became part of the root set,
354 * we can't rely on the thread-local trackedAlloc table, so
355 * we can't keep track of a real allocated OOME object. But, since
356 * the thread is in the process of being created, it won't have
357 * a useful stack anyway, so we may as well make things easier
358 * by throwing the (stackless) pre-built OOME.
359 */
360 if (dvmIsOnThreadList(self) && !self->throwingOOME) {
361 /* Let ourselves know that we tried to throw an OOM
362 * error in the normal way in case we run out of
363 * memory trying to allocate it inside dvmThrowException().
364 */
365 self->throwingOOME = true;
366
367 /* Don't include a description string;
368 * one fewer allocation.
369 */
370 dvmThrowException("Ljava/lang/OutOfMemoryError;", NULL);
371 } else {
372 /*
373 * This thread has already tried to throw an OutOfMemoryError,
374 * which probably means that we're running out of memory
375 * while recursively trying to throw.
376 *
377 * To avoid any more allocation attempts, "throw" a pre-built
378 * OutOfMemoryError object (which won't have a useful stack trace).
379 *
380 * Note that since this call can't possibly allocate anything,
381 * we don't care about the state of self->throwingOOME
382 * (which will usually already be set).
383 */
384 dvmSetException(self, gDvm.outOfMemoryObj);
385 }
386 /* We're done with the possible recursion.
387 */
388 self->throwingOOME = false;
389 }
390}
391
392/*
393 * Allocate storage on the GC heap. We guarantee 8-byte alignment.
394 *
395 * The new storage is zeroed out.
396 *
397 * Note that, in rare cases, this could get called while a GC is in
398 * progress. If a non-VM thread tries to attach itself through JNI,
399 * it will need to allocate some objects. If this becomes annoying to
400 * deal with, we can block it at the source, but holding the allocation
401 * mutex should be enough.
402 *
403 * In rare circumstances (JNI AttachCurrentThread) we can be called
404 * from a non-VM thread.
405 *
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800406 * Use ALLOC_DONT_TRACK when we either don't want to track an allocation
407 * (because it's being done for the interpreter "new" operation and will
408 * be part of the root set immediately) or we can't (because this allocation
409 * is for a brand new thread).
410 *
411 * Returns NULL and throws an exception on failure.
412 *
413 * TODO: don't do a GC if the debugger thinks all threads are suspended
414 */
415void* dvmMalloc(size_t size, int flags)
416{
417 GcHeap *gcHeap = gDvm.gcHeap;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800418 void *ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800419
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800420#if defined(WITH_ALLOC_LIMITS)
421 /*
422 * See if they've exceeded the allocation limit for this thread.
423 *
424 * A limit value of -1 means "no limit".
425 *
426 * This is enabled at compile time because it requires us to do a
427 * TLS lookup for the Thread pointer. This has enough of a performance
428 * impact that we don't want to do it if we don't have to. (Now that
429 * we're using gDvm.checkAllocLimits we may want to reconsider this,
430 * but it's probably still best to just compile the check out of
431 * production code -- one less thing to hit on every allocation.)
432 */
433 if (gDvm.checkAllocLimits) {
434 Thread* self = dvmThreadSelf();
435 if (self != NULL) {
436 int count = self->allocLimit;
437 if (count > 0) {
438 self->allocLimit--;
439 } else if (count == 0) {
440 /* fail! */
441 assert(!gDvm.initializing);
442 self->allocLimit = -1;
443 dvmThrowException("Ldalvik/system/AllocationLimitError;",
444 "thread allocation limit exceeded");
445 return NULL;
446 }
447 }
448 }
449
450 if (gDvm.allocationLimit >= 0) {
451 assert(!gDvm.initializing);
452 gDvm.allocationLimit = -1;
453 dvmThrowException("Ldalvik/system/AllocationLimitError;",
454 "global allocation limit exceeded");
455 return NULL;
456 }
457#endif
458
459 dvmLockHeap();
460
461 /* Try as hard as possible to allocate some memory.
462 */
Carl Shapiro6343bd02010-02-16 17:40:19 -0800463 ptr = tryMalloc(size);
464 if (ptr != NULL) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800465 /* We've got the memory.
466 */
467 if ((flags & ALLOC_FINALIZABLE) != 0) {
468 /* This object is an instance of a class that
469 * overrides finalize(). Add it to the finalizable list.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800470 */
471 if (!dvmHeapAddRefToLargeTable(&gcHeap->finalizableRefs,
Carl Shapiro6343bd02010-02-16 17:40:19 -0800472 (Object *)ptr))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800473 {
474 LOGE_HEAP("dvmMalloc(): no room for any more "
475 "finalizable objects\n");
476 dvmAbort();
477 }
478 }
479
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800480#ifdef WITH_PROFILER
481 if (gDvm.allocProf.enabled) {
482 Thread* self = dvmThreadSelf();
483 gDvm.allocProf.allocCount++;
484 gDvm.allocProf.allocSize += size;
485 if (self != NULL) {
486 self->allocProf.allocCount++;
487 self->allocProf.allocSize += size;
488 }
489 }
490#endif
491 } else {
492 /* The allocation failed.
493 */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800494
495#ifdef WITH_PROFILER
496 if (gDvm.allocProf.enabled) {
497 Thread* self = dvmThreadSelf();
498 gDvm.allocProf.failedAllocCount++;
499 gDvm.allocProf.failedAllocSize += size;
500 if (self != NULL) {
501 self->allocProf.failedAllocCount++;
502 self->allocProf.failedAllocSize += size;
503 }
504 }
505#endif
506 }
507
508 dvmUnlockHeap();
509
510 if (ptr != NULL) {
511 /*
Barry Hayesd4f78d32010-06-08 09:34:42 -0700512 * If caller hasn't asked us not to track it, add it to the
513 * internal tracking list.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800514 */
Barry Hayesd4f78d32010-06-08 09:34:42 -0700515 if ((flags & ALLOC_DONT_TRACK) == 0) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800516 dvmAddTrackedAlloc(ptr, NULL);
517 }
518 } else {
Ben Chengc3b92b22010-01-26 16:46:15 -0800519 /*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800520 * The allocation failed; throw an OutOfMemoryError.
521 */
522 throwOOME();
523 }
524
525 return ptr;
526}
527
528/*
529 * Returns true iff <obj> points to a valid allocated object.
530 */
531bool dvmIsValidObject(const Object* obj)
532{
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800533 /* Don't bother if it's NULL or not 8-byte aligned.
534 */
Carl Shapiro6343bd02010-02-16 17:40:19 -0800535 if (obj != NULL && ((uintptr_t)obj & (8-1)) == 0) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800536 /* Even if the heap isn't locked, this shouldn't return
537 * any false negatives. The only mutation that could
538 * be happening is allocation, which means that another
539 * thread could be in the middle of a read-modify-write
540 * to add a new bit for a new object. However, that
541 * RMW will have completed by the time any other thread
542 * could possibly see the new pointer, so there is no
543 * danger of dvmIsValidObject() being called on a valid
544 * pointer whose bit isn't set.
545 *
546 * Freeing will only happen during the sweep phase, which
547 * only happens while the heap is locked.
548 */
Carl Shapiro6343bd02010-02-16 17:40:19 -0800549 return dvmHeapSourceContains(obj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800550 }
551 return false;
552}
553
Barry Hayes364f9d92010-06-11 16:12:47 -0700554/*
555 * Returns true iff <obj> points to a word-aligned address within Heap
556 * address space.
557 */
558bool dvmIsValidObjectAddress(const void* ptr)
559{
560 /* Don't bother if it's not 4-byte aligned.
561 */
562 if (((uintptr_t)ptr & (4-1)) == 0) {
563 return dvmHeapSourceContainsAddress(ptr);
564 }
565 return false;
566}
567
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800568size_t dvmObjectSizeInHeap(const Object *obj)
569{
Carl Shapiro6343bd02010-02-16 17:40:19 -0800570 return dvmHeapSourceChunkSize(obj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800571}
572
573/*
Barry Hayes962adba2010-03-17 12:12:39 -0700574 * Scan every live object in the heap, holding the locks.
575 */
576static void verifyHeap()
577{
578 // TODO: check the locks.
579 HeapBitmap *liveBits = dvmHeapSourceGetLiveBits();
580 dvmVerifyBitmap(liveBits);
581}
582
583/*
584 * Suspend the VM as for a GC, and assert-fail if any object has any
585 * corrupt references.
586 */
587void dvmHeapSuspendAndVerify()
588{
589 /* Suspend the VM. */
590 dvmSuspendAllThreads(SUSPEND_FOR_VERIFY);
591 dvmLockMutex(&gDvm.heapWorkerLock);
592 dvmAssertHeapWorkerThreadRunning();
593 dvmLockMutex(&gDvm.heapWorkerListLock);
594
595 verifyHeap();
596
597 /* Resume the VM. */
598 dvmUnlockMutex(&gDvm.heapWorkerListLock);
599 dvmUnlockMutex(&gDvm.heapWorkerLock);
600 dvmResumeAllThreads(SUSPEND_FOR_VERIFY);
601}
602
603/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800604 * Initiate garbage collection.
605 *
606 * NOTES:
607 * - If we don't hold gDvm.threadListLock, it's possible for a thread to
608 * be added to the thread list while we work. The thread should NOT
609 * start executing, so this is only interesting when we start chasing
610 * thread stacks. (Before we do so, grab the lock.)
611 *
612 * We are not allowed to GC when the debugger has suspended the VM, which
613 * is awkward because debugger requests can cause allocations. The easiest
614 * way to enforce this is to refuse to GC on an allocation made by the
615 * JDWP thread -- we have to expand the heap or fail.
616 */
Carl Shapiro29540742010-03-26 15:34:39 -0700617void dvmCollectGarbageInternal(bool clearSoftRefs, GcReason reason)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800618{
619 GcHeap *gcHeap = gDvm.gcHeap;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800620 u8 now;
621 s8 timeSinceLastGc;
622 s8 gcElapsedTime;
623 int numFreed;
624 size_t sizeFreed;
Carl Shapirod25566d2010-03-11 20:39:47 -0800625 GcMode gcMode;
Carl Shapiroec805ea2010-06-28 16:28:26 -0700626 int oldThreadPriority = kInvalidPriority;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800627
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800628 /* The heap lock must be held.
629 */
630
631 if (gcHeap->gcRunning) {
632 LOGW_HEAP("Attempted recursive GC\n");
633 return;
634 }
Carl Shapirod25566d2010-03-11 20:39:47 -0800635 gcMode = (reason == GC_FOR_MALLOC) ? GC_PARTIAL : GC_FULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800636 gcHeap->gcRunning = true;
637 now = dvmGetRelativeTimeUsec();
638 if (gcHeap->gcStartTime != 0) {
639 timeSinceLastGc = (now - gcHeap->gcStartTime) / 1000;
640 } else {
641 timeSinceLastGc = 0;
642 }
643 gcHeap->gcStartTime = now;
644
Barry Hayes1b9b4e42010-01-04 10:33:46 -0800645 LOGV_HEAP("%s starting -- suspending threads\n", GcReasonStr[reason]);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800646
647 dvmSuspendAllThreads(SUSPEND_FOR_GC);
648
Carl Shapiroec805ea2010-06-28 16:28:26 -0700649 /*
650 * If we are not marking concurrently raise the priority of the
651 * thread performing the garbage collection.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800652 */
Carl Shapiroec805ea2010-06-28 16:28:26 -0700653 if (reason != GC_CONCURRENT) {
654 /* Get the priority (the "nice" value) of the current thread. The
655 * getpriority() call can legitimately return -1, so we have to
656 * explicitly test errno.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800657 */
Carl Shapiroec805ea2010-06-28 16:28:26 -0700658 errno = 0;
659 int priorityResult = getpriority(PRIO_PROCESS, 0);
660 if (errno != 0) {
661 LOGI_HEAP("getpriority(self) failed: %s\n", strerror(errno));
662 } else if (priorityResult > ANDROID_PRIORITY_NORMAL) {
663 /* Current value is numerically greater than "normal", which
664 * in backward UNIX terms means lower priority.
665 */
San Mehat256fc152009-04-21 14:03:06 -0700666
Carl Shapiroec805ea2010-06-28 16:28:26 -0700667 if (priorityResult >= ANDROID_PRIORITY_BACKGROUND) {
668 set_sched_policy(dvmGetSysThreadId(), SP_FOREGROUND);
669 }
San Mehat256fc152009-04-21 14:03:06 -0700670
Carl Shapiroec805ea2010-06-28 16:28:26 -0700671 if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL) != 0) {
672 LOGI_HEAP("Unable to elevate priority from %d to %d\n",
673 priorityResult, ANDROID_PRIORITY_NORMAL);
674 } else {
675 /* priority elevated; save value so we can restore it later */
676 LOGD_HEAP("Elevating priority from %d to %d\n",
677 priorityResult, ANDROID_PRIORITY_NORMAL);
678 oldThreadPriority = priorityResult;
679 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800680 }
681 }
682
683 /* Wait for the HeapWorker thread to block.
684 * (It may also already be suspended in interp code,
685 * in which case it's not holding heapWorkerLock.)
686 */
687 dvmLockMutex(&gDvm.heapWorkerLock);
688
689 /* Make sure that the HeapWorker thread hasn't become
690 * wedged inside interp code. If it has, this call will
691 * print a message and abort the VM.
692 */
693 dvmAssertHeapWorkerThreadRunning();
694
695 /* Lock the pendingFinalizationRefs list.
696 *
697 * Acquire the lock after suspending so the finalizer
698 * thread can't block in the RUNNING state while
699 * we try to suspend.
700 */
701 dvmLockMutex(&gDvm.heapWorkerListLock);
702
Barry Hayes962adba2010-03-17 12:12:39 -0700703 if (gDvm.preVerify) {
704 LOGV_HEAP("Verifying heap before GC");
705 verifyHeap();
706 }
707
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800708#ifdef WITH_PROFILER
709 dvmMethodTraceGCBegin();
710#endif
711
712#if WITH_HPROF
713
714/* Set DUMP_HEAP_ON_DDMS_UPDATE to 1 to enable heap dumps
715 * whenever DDMS requests a heap update (HPIF chunk).
716 * The output files will appear in /data/misc, which must
717 * already exist.
718 * You must define "WITH_HPROF := true" in your buildspec.mk
719 * and recompile libdvm for this to work.
720 *
721 * To enable stack traces for each allocation, define
722 * "WITH_HPROF_STACK := true" in buildspec.mk. This option slows down
723 * allocations and also requires 8 additional bytes per object on the
724 * GC heap.
725 */
726#define DUMP_HEAP_ON_DDMS_UPDATE 0
727#if DUMP_HEAP_ON_DDMS_UPDATE
728 gcHeap->hprofDumpOnGc |= (gcHeap->ddmHpifWhen != 0);
729#endif
730
731 if (gcHeap->hprofDumpOnGc) {
732 char nameBuf[128];
733
The Android Open Source Project99409882009-03-18 22:20:24 -0700734 gcHeap->hprofResult = -1;
735
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800736 if (gcHeap->hprofFileName == NULL) {
737 /* no filename was provided; invent one */
738 sprintf(nameBuf, "/data/misc/heap-dump-tm%d-pid%d.hprof",
739 (int) time(NULL), (int) getpid());
740 gcHeap->hprofFileName = nameBuf;
741 }
Andy McFadden6bf992c2010-01-28 17:01:39 -0800742 gcHeap->hprofContext = hprofStartup(gcHeap->hprofFileName,
743 gcHeap->hprofDirectToDdms);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800744 if (gcHeap->hprofContext != NULL) {
745 hprofStartHeapDump(gcHeap->hprofContext);
746 }
747 gcHeap->hprofDumpOnGc = false;
748 gcHeap->hprofFileName = NULL;
749 }
750#endif
751
752 if (timeSinceLastGc < 10000) {
753 LOGD_HEAP("GC! (%dms since last GC)\n",
754 (int)timeSinceLastGc);
755 } else {
756 LOGD_HEAP("GC! (%d sec since last GC)\n",
757 (int)(timeSinceLastGc / 1000));
758 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800759
760 /* Set up the marking context.
761 */
Carl Shapirod25566d2010-03-11 20:39:47 -0800762 if (!dvmHeapBeginMarkStep(gcMode)) {
The Android Open Source Project99409882009-03-18 22:20:24 -0700763 LOGE_HEAP("dvmHeapBeginMarkStep failed; aborting\n");
764 dvmAbort();
765 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800766
767 /* Mark the set of objects that are strongly reachable from the roots.
768 */
769 LOGD_HEAP("Marking...");
770 dvmHeapMarkRootSet();
771
772 /* dvmHeapScanMarkedObjects() will build the lists of known
773 * instances of the Reference classes.
774 */
775 gcHeap->softReferences = NULL;
776 gcHeap->weakReferences = NULL;
777 gcHeap->phantomReferences = NULL;
778
Carl Shapiroec805ea2010-06-28 16:28:26 -0700779 if (reason == GC_CONCURRENT) {
780 /*
781 * We are performing a concurrent collection. Resume all
782 * threads for the duration of the recursive mark.
783 */
784 dvmResumeAllThreads(SUSPEND_FOR_GC);
785 }
786
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800787 /* Recursively mark any objects that marked objects point to strongly.
788 * If we're not collecting soft references, soft-reachable
789 * objects will also be marked.
790 */
791 LOGD_HEAP("Recursing...");
792 dvmHeapScanMarkedObjects();
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800793
Carl Shapiroec805ea2010-06-28 16:28:26 -0700794 if (reason == GC_CONCURRENT) {
795 /*
796 * We are performing a concurrent collection. Perform the
797 * final thread suspension.
798 */
799 dvmSuspendAllThreads(SUSPEND_FOR_GC);
800 /*
801 * As no barrier intercepts root updates, we conservatively
802 * assume all roots may be gray and re-mark them.
803 */
804 dvmHeapMarkRootSet();
805 /*
806 * Recursively mark gray objects pointed to by the roots or by
807 * heap objects dirtied during the concurrent mark.
808 */
809 dvmMarkDirtyObjects();
810 }
811
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800812 /* All strongly-reachable objects have now been marked.
813 */
Carl Shapiro29540742010-03-26 15:34:39 -0700814 LOGD_HEAP("Handling soft references...");
815 if (!clearSoftRefs) {
816 dvmHandleSoftRefs(&gcHeap->softReferences);
817 }
818 dvmClearWhiteRefs(&gcHeap->softReferences);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800819
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800820 LOGD_HEAP("Handling weak references...");
Carl Shapiro29540742010-03-26 15:34:39 -0700821 dvmClearWhiteRefs(&gcHeap->weakReferences);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800822
823 /* Once all weak-reachable objects have been taken
824 * care of, any remaining unmarked objects can be finalized.
825 */
826 LOGD_HEAP("Finding finalizations...");
827 dvmHeapScheduleFinalizations();
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800828
Carl Shapiro29540742010-03-26 15:34:39 -0700829 LOGD_HEAP("Handling f-reachable soft references...");
830 dvmClearWhiteRefs(&gcHeap->softReferences);
831
832 LOGD_HEAP("Handling f-reachable weak references...");
833 dvmClearWhiteRefs(&gcHeap->weakReferences);
834
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800835 /* Any remaining objects that are not pending finalization
836 * could be phantom-reachable. This will mark any phantom-reachable
837 * objects, as well as enqueue their references.
838 */
839 LOGD_HEAP("Handling phantom references...");
Carl Shapiro29540742010-03-26 15:34:39 -0700840 dvmClearWhiteRefs(&gcHeap->phantomReferences);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800841
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800842#ifdef WITH_DEADLOCK_PREDICTION
843 dvmDumpMonitorInfo("before sweep");
844#endif
845 LOGD_HEAP("Sweeping...");
Carl Shapirod25566d2010-03-11 20:39:47 -0800846 dvmHeapSweepUnmarkedObjects(gcMode, &numFreed, &sizeFreed);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800847#ifdef WITH_DEADLOCK_PREDICTION
848 dvmDumpMonitorInfo("after sweep");
849#endif
850
851 LOGD_HEAP("Cleaning up...");
852 dvmHeapFinishMarkStep();
853
854 LOGD_HEAP("Done.");
855
856 /* Now's a good time to adjust the heap size, since
857 * we know what our utilization is.
858 *
859 * This doesn't actually resize any memory;
860 * it just lets the heap grow more when necessary.
861 */
862 dvmHeapSourceGrowForUtilization();
863 dvmHeapSizeChanged();
864
865#if WITH_HPROF
866 if (gcHeap->hprofContext != NULL) {
867 hprofFinishHeapDump(gcHeap->hprofContext);
868//TODO: write a HEAP_SUMMARY record
The Android Open Source Project99409882009-03-18 22:20:24 -0700869 if (hprofShutdown(gcHeap->hprofContext))
870 gcHeap->hprofResult = 0; /* indicate success */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800871 gcHeap->hprofContext = NULL;
872 }
873#endif
874
875 /* Now that we've freed up the GC heap, return any large
876 * free chunks back to the system. They'll get paged back
877 * in the next time they're used. Don't do it immediately,
878 * though; if the process is still allocating a bunch of
879 * memory, we'll be taking a ton of page faults that we don't
880 * necessarily need to.
881 *
882 * Cancel any old scheduled trims, and schedule a new one.
883 */
884 dvmScheduleHeapSourceTrim(5); // in seconds
885
886#ifdef WITH_PROFILER
887 dvmMethodTraceGCEnd();
888#endif
Barry Hayes962adba2010-03-17 12:12:39 -0700889 LOGV_HEAP("GC finished");
890
891 if (gDvm.postVerify) {
892 LOGV_HEAP("Verifying heap after GC");
893 verifyHeap();
894 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800895
896 gcHeap->gcRunning = false;
897
Barry Hayes962adba2010-03-17 12:12:39 -0700898 LOGV_HEAP("Resuming threads");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800899 dvmUnlockMutex(&gDvm.heapWorkerListLock);
900 dvmUnlockMutex(&gDvm.heapWorkerLock);
901
Ben Chengc3b92b22010-01-26 16:46:15 -0800902#if defined(WITH_JIT)
Ben Chengc3b92b22010-01-26 16:46:15 -0800903 /*
904 * Patching a chaining cell is very cheap as it only updates 4 words. It's
905 * the overhead of stopping all threads and synchronizing the I/D cache
906 * that makes it expensive.
907 *
908 * Therefore we batch those work orders in a queue and go through them
909 * when threads are suspended for GC.
910 */
911 dvmCompilerPerformSafePointChecks();
912#endif
913
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800914 dvmResumeAllThreads(SUSPEND_FOR_GC);
Carl Shapiroec805ea2010-06-28 16:28:26 -0700915 if (reason != GC_CONCURRENT) {
916 if (oldThreadPriority != kInvalidPriority) {
917 if (setpriority(PRIO_PROCESS, 0, oldThreadPriority) != 0) {
918 LOGW_HEAP("Unable to reset priority to %d: %s\n",
919 oldThreadPriority, strerror(errno));
920 } else {
921 LOGD_HEAP("Reset priority to %d\n", oldThreadPriority);
922 }
San Mehat256fc152009-04-21 14:03:06 -0700923
Carl Shapiroec805ea2010-06-28 16:28:26 -0700924 if (oldThreadPriority >= ANDROID_PRIORITY_BACKGROUND) {
925 set_sched_policy(dvmGetSysThreadId(), SP_BACKGROUND);
926 }
San Mehat256fc152009-04-21 14:03:06 -0700927 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800928 }
929 gcElapsedTime = (dvmGetRelativeTimeUsec() - gcHeap->gcStartTime) / 1000;
Barry Hayes31364132010-01-04 16:10:09 -0800930 LOGD("%s freed %d objects / %zd bytes in %dms\n",
931 GcReasonStr[reason], numFreed, sizeFreed, (int)gcElapsedTime);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800932 dvmLogGcStats(numFreed, sizeFreed, gcElapsedTime);
933
934 if (gcHeap->ddmHpifWhen != 0) {
935 LOGD_HEAP("Sending VM heap info to DDM\n");
936 dvmDdmSendHeapInfo(gcHeap->ddmHpifWhen, false);
937 }
938 if (gcHeap->ddmHpsgWhen != 0) {
939 LOGD_HEAP("Dumping VM heap to DDM\n");
940 dvmDdmSendHeapSegments(false, false);
941 }
942 if (gcHeap->ddmNhsgWhen != 0) {
943 LOGD_HEAP("Dumping native heap to DDM\n");
944 dvmDdmSendHeapSegments(false, true);
945 }
946}
947
948#if WITH_HPROF
949/*
950 * Perform garbage collection, writing heap information to the specified file.
951 *
952 * If "fileName" is NULL, a suitable name will be generated automatically.
The Android Open Source Project99409882009-03-18 22:20:24 -0700953 *
954 * Returns 0 on success, or an error code on failure.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800955 */
Andy McFadden6bf992c2010-01-28 17:01:39 -0800956int hprofDumpHeap(const char* fileName, bool directToDdms)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800957{
The Android Open Source Project99409882009-03-18 22:20:24 -0700958 int result;
959
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800960 dvmLockMutex(&gDvm.gcHeapLock);
961
962 gDvm.gcHeap->hprofDumpOnGc = true;
963 gDvm.gcHeap->hprofFileName = fileName;
Andy McFadden6bf992c2010-01-28 17:01:39 -0800964 gDvm.gcHeap->hprofDirectToDdms = directToDdms;
Barry Hayes1b9b4e42010-01-04 10:33:46 -0800965 dvmCollectGarbageInternal(false, GC_HPROF_DUMP_HEAP);
The Android Open Source Project99409882009-03-18 22:20:24 -0700966 result = gDvm.gcHeap->hprofResult;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800967
968 dvmUnlockMutex(&gDvm.gcHeapLock);
The Android Open Source Project99409882009-03-18 22:20:24 -0700969
970 return result;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800971}
972
973void dvmHeapSetHprofGcScanState(hprof_heap_tag_t state, u4 threadSerialNumber)
974{
975 if (gDvm.gcHeap->hprofContext != NULL) {
976 hprofSetGcScanState(gDvm.gcHeap->hprofContext, state,
977 threadSerialNumber);
978 }
979}
980#endif