blob: 32b4d3b46428d61382f8859beb07748f4aee1ca5 [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
193 obj = NULL;
194
195 dvmLockMutex(&gDvm.heapWorkerListLock);
196
197 /* We must handle reference operations before finalizations.
198 * If:
199 * a) Someone subclasses WeakReference and overrides clear()
200 * b) A reference of this type is the last reference to
201 * a finalizable object
202 * then we need to guarantee that the overridden clear() is called
203 * on the reference before finalize() is called on the referent.
204 * Both of these operations will always be scheduled at the same
205 * time, so handling reference operations first will guarantee
206 * the required order.
207 */
208 obj = dvmHeapGetNextObjectFromLargeTable(&gcHeap->referenceOperations);
209 if (obj != NULL) {
210 uintptr_t workBits;
211
Barry Hayes6930a112009-12-22 11:01:38 -0800212 workBits = (uintptr_t)obj & WORKER_ENQUEUE;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800213 assert(workBits != 0);
Barry Hayes6930a112009-12-22 11:01:38 -0800214 obj = (Object *)((uintptr_t)obj & ~WORKER_ENQUEUE);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800215
216 *op = workBits;
217 } else {
218 obj = dvmHeapGetNextObjectFromLargeTable(
219 &gcHeap->pendingFinalizationRefs);
220 if (obj != NULL) {
221 *op = WORKER_FINALIZE;
222 }
223 }
224
225 if (obj != NULL) {
226 /* Don't let the GC collect the object until the
227 * worker thread is done with it.
228 *
229 * This call is safe; it uses thread-local storage
230 * and doesn't acquire any locks.
231 */
232 dvmAddTrackedAlloc(obj, NULL);
233 }
234
235 dvmUnlockMutex(&gDvm.heapWorkerListLock);
236
237 return obj;
238}
239
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800240/* Whenever the effective heap size may have changed,
241 * this function must be called.
242 */
243void dvmHeapSizeChanged()
244{
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800245}
246
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800247/* Do a full garbage collection, which may grow the
248 * heap as a side-effect if the live set is large.
249 */
250static void gcForMalloc(bool collectSoftReferences)
251{
252#ifdef WITH_PROFILER
253 if (gDvm.allocProf.enabled) {
254 Thread* self = dvmThreadSelf();
255 gDvm.allocProf.gcCount++;
256 if (self != NULL) {
257 self->allocProf.gcCount++;
258 }
259 }
260#endif
261 /* This may adjust the soft limit as a side-effect.
262 */
263 LOGD_HEAP("dvmMalloc initiating GC%s\n",
264 collectSoftReferences ? "(collect SoftReferences)" : "");
Barry Hayes1b9b4e42010-01-04 10:33:46 -0800265 dvmCollectGarbageInternal(collectSoftReferences, GC_FOR_MALLOC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800266}
267
268/* Try as hard as possible to allocate some memory.
269 */
Carl Shapiro6343bd02010-02-16 17:40:19 -0800270static void *tryMalloc(size_t size)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800271{
Carl Shapiro6343bd02010-02-16 17:40:19 -0800272 void *ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800273
274 /* Don't try too hard if there's no way the allocation is
275 * going to succeed. We have to collect SoftReferences before
276 * throwing an OOME, though.
277 */
278 if (size >= gDvm.heapSizeMax) {
279 LOGW_HEAP("dvmMalloc(%zu/0x%08zx): "
280 "someone's allocating a huge buffer\n", size, size);
Carl Shapiro6343bd02010-02-16 17:40:19 -0800281 ptr = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800282 goto collect_soft_refs;
283 }
284
285//TODO: figure out better heuristics
286// There will be a lot of churn if someone allocates a bunch of
287// big objects in a row, and we hit the frag case each time.
288// A full GC for each.
289// Maybe we grow the heap in bigger leaps
290// Maybe we skip the GC if the size is large and we did one recently
291// (number of allocations ago) (watch for thread effects)
292// DeflateTest allocs a bunch of ~128k buffers w/in 0-5 allocs of each other
293// (or, at least, there are only 0-5 objects swept each time)
294
Carl Shapiro6343bd02010-02-16 17:40:19 -0800295 ptr = dvmHeapSourceAlloc(size);
296 if (ptr != NULL) {
297 return ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800298 }
299
300 /* The allocation failed. Free up some space by doing
301 * a full garbage collection. This may grow the heap
302 * if the live set is sufficiently large.
303 */
304 gcForMalloc(false);
Carl Shapiro6343bd02010-02-16 17:40:19 -0800305 ptr = dvmHeapSourceAlloc(size);
306 if (ptr != NULL) {
307 return ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800308 }
309
310 /* Even that didn't work; this is an exceptional state.
311 * Try harder, growing the heap if necessary.
312 */
Carl Shapiro6343bd02010-02-16 17:40:19 -0800313 ptr = dvmHeapSourceAllocAndGrow(size);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800314 dvmHeapSizeChanged();
Carl Shapiro6343bd02010-02-16 17:40:19 -0800315 if (ptr != NULL) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800316 size_t newHeapSize;
317
318 newHeapSize = dvmHeapSourceGetIdealFootprint();
319//TODO: may want to grow a little bit more so that the amount of free
320// space is equal to the old free space + the utilization slop for
321// the new allocation.
322 LOGI_HEAP("Grow heap (frag case) to "
323 "%zu.%03zuMB for %zu-byte allocation\n",
324 FRACTIONAL_MB(newHeapSize), size);
Carl Shapiro6343bd02010-02-16 17:40:19 -0800325 return ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800326 }
327
328 /* Most allocations should have succeeded by now, so the heap
329 * is really full, really fragmented, or the requested size is
330 * really big. Do another GC, collecting SoftReferences this
331 * time. The VM spec requires that all SoftReferences have
332 * been collected and cleared before throwing an OOME.
333 */
334//TODO: wait for the finalizers from the previous GC to finish
335collect_soft_refs:
336 LOGI_HEAP("Forcing collection of SoftReferences for %zu-byte allocation\n",
337 size);
338 gcForMalloc(true);
Carl Shapiro6343bd02010-02-16 17:40:19 -0800339 ptr = dvmHeapSourceAllocAndGrow(size);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800340 dvmHeapSizeChanged();
Carl Shapiro6343bd02010-02-16 17:40:19 -0800341 if (ptr != NULL) {
342 return ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800343 }
344//TODO: maybe wait for finalizers and try one last time
345
346 LOGE_HEAP("Out of memory on a %zd-byte allocation.\n", size);
347//TODO: tell the HeapSource to dump its state
348 dvmDumpThread(dvmThreadSelf(), false);
349
350 return NULL;
351}
352
353/* Throw an OutOfMemoryError if there's a thread to attach it to.
354 * Avoid recursing.
355 *
356 * The caller must not be holding the heap lock, or else the allocations
357 * in dvmThrowException() will deadlock.
358 */
359static void throwOOME()
360{
361 Thread *self;
362
363 if ((self = dvmThreadSelf()) != NULL) {
364 /* If the current (failing) dvmMalloc() happened as part of thread
365 * creation/attachment before the thread became part of the root set,
366 * we can't rely on the thread-local trackedAlloc table, so
367 * we can't keep track of a real allocated OOME object. But, since
368 * the thread is in the process of being created, it won't have
369 * a useful stack anyway, so we may as well make things easier
370 * by throwing the (stackless) pre-built OOME.
371 */
372 if (dvmIsOnThreadList(self) && !self->throwingOOME) {
373 /* Let ourselves know that we tried to throw an OOM
374 * error in the normal way in case we run out of
375 * memory trying to allocate it inside dvmThrowException().
376 */
377 self->throwingOOME = true;
378
379 /* Don't include a description string;
380 * one fewer allocation.
381 */
382 dvmThrowException("Ljava/lang/OutOfMemoryError;", NULL);
383 } else {
384 /*
385 * This thread has already tried to throw an OutOfMemoryError,
386 * which probably means that we're running out of memory
387 * while recursively trying to throw.
388 *
389 * To avoid any more allocation attempts, "throw" a pre-built
390 * OutOfMemoryError object (which won't have a useful stack trace).
391 *
392 * Note that since this call can't possibly allocate anything,
393 * we don't care about the state of self->throwingOOME
394 * (which will usually already be set).
395 */
396 dvmSetException(self, gDvm.outOfMemoryObj);
397 }
398 /* We're done with the possible recursion.
399 */
400 self->throwingOOME = false;
401 }
402}
403
404/*
405 * Allocate storage on the GC heap. We guarantee 8-byte alignment.
406 *
407 * The new storage is zeroed out.
408 *
409 * Note that, in rare cases, this could get called while a GC is in
410 * progress. If a non-VM thread tries to attach itself through JNI,
411 * it will need to allocate some objects. If this becomes annoying to
412 * deal with, we can block it at the source, but holding the allocation
413 * mutex should be enough.
414 *
415 * In rare circumstances (JNI AttachCurrentThread) we can be called
416 * from a non-VM thread.
417 *
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800418 * Use ALLOC_DONT_TRACK when we either don't want to track an allocation
419 * (because it's being done for the interpreter "new" operation and will
420 * be part of the root set immediately) or we can't (because this allocation
421 * is for a brand new thread).
422 *
423 * Returns NULL and throws an exception on failure.
424 *
425 * TODO: don't do a GC if the debugger thinks all threads are suspended
426 */
427void* dvmMalloc(size_t size, int flags)
428{
429 GcHeap *gcHeap = gDvm.gcHeap;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800430 void *ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800431
432#if 0
433 /* handy for spotting large allocations */
434 if (size >= 100000) {
435 LOGI("dvmMalloc(%d):\n", size);
436 dvmDumpThread(dvmThreadSelf(), false);
437 }
438#endif
439
440#if defined(WITH_ALLOC_LIMITS)
441 /*
442 * See if they've exceeded the allocation limit for this thread.
443 *
444 * A limit value of -1 means "no limit".
445 *
446 * This is enabled at compile time because it requires us to do a
447 * TLS lookup for the Thread pointer. This has enough of a performance
448 * impact that we don't want to do it if we don't have to. (Now that
449 * we're using gDvm.checkAllocLimits we may want to reconsider this,
450 * but it's probably still best to just compile the check out of
451 * production code -- one less thing to hit on every allocation.)
452 */
453 if (gDvm.checkAllocLimits) {
454 Thread* self = dvmThreadSelf();
455 if (self != NULL) {
456 int count = self->allocLimit;
457 if (count > 0) {
458 self->allocLimit--;
459 } else if (count == 0) {
460 /* fail! */
461 assert(!gDvm.initializing);
462 self->allocLimit = -1;
463 dvmThrowException("Ldalvik/system/AllocationLimitError;",
464 "thread allocation limit exceeded");
465 return NULL;
466 }
467 }
468 }
469
470 if (gDvm.allocationLimit >= 0) {
471 assert(!gDvm.initializing);
472 gDvm.allocationLimit = -1;
473 dvmThrowException("Ldalvik/system/AllocationLimitError;",
474 "global allocation limit exceeded");
475 return NULL;
476 }
477#endif
478
479 dvmLockHeap();
480
481 /* Try as hard as possible to allocate some memory.
482 */
Carl Shapiro6343bd02010-02-16 17:40:19 -0800483 ptr = tryMalloc(size);
484 if (ptr != NULL) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800485 /* We've got the memory.
486 */
487 if ((flags & ALLOC_FINALIZABLE) != 0) {
488 /* This object is an instance of a class that
489 * overrides finalize(). Add it to the finalizable list.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800490 */
491 if (!dvmHeapAddRefToLargeTable(&gcHeap->finalizableRefs,
Carl Shapiro6343bd02010-02-16 17:40:19 -0800492 (Object *)ptr))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800493 {
494 LOGE_HEAP("dvmMalloc(): no room for any more "
495 "finalizable objects\n");
496 dvmAbort();
497 }
498 }
499
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800500#ifdef WITH_PROFILER
501 if (gDvm.allocProf.enabled) {
502 Thread* self = dvmThreadSelf();
503 gDvm.allocProf.allocCount++;
504 gDvm.allocProf.allocSize += size;
505 if (self != NULL) {
506 self->allocProf.allocCount++;
507 self->allocProf.allocSize += size;
508 }
509 }
510#endif
511 } else {
512 /* The allocation failed.
513 */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800514
515#ifdef WITH_PROFILER
516 if (gDvm.allocProf.enabled) {
517 Thread* self = dvmThreadSelf();
518 gDvm.allocProf.failedAllocCount++;
519 gDvm.allocProf.failedAllocSize += size;
520 if (self != NULL) {
521 self->allocProf.failedAllocCount++;
522 self->allocProf.failedAllocSize += size;
523 }
524 }
525#endif
526 }
527
528 dvmUnlockHeap();
529
530 if (ptr != NULL) {
531 /*
Barry Hayesd4f78d32010-06-08 09:34:42 -0700532 * If caller hasn't asked us not to track it, add it to the
533 * internal tracking list.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800534 */
Barry Hayesd4f78d32010-06-08 09:34:42 -0700535 if ((flags & ALLOC_DONT_TRACK) == 0) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800536 dvmAddTrackedAlloc(ptr, NULL);
537 }
538 } else {
Ben Chengc3b92b22010-01-26 16:46:15 -0800539 /*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800540 * The allocation failed; throw an OutOfMemoryError.
541 */
542 throwOOME();
543 }
544
545 return ptr;
546}
547
548/*
549 * Returns true iff <obj> points to a valid allocated object.
550 */
551bool dvmIsValidObject(const Object* obj)
552{
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800553 /* Don't bother if it's NULL or not 8-byte aligned.
554 */
Carl Shapiro6343bd02010-02-16 17:40:19 -0800555 if (obj != NULL && ((uintptr_t)obj & (8-1)) == 0) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800556 /* Even if the heap isn't locked, this shouldn't return
557 * any false negatives. The only mutation that could
558 * be happening is allocation, which means that another
559 * thread could be in the middle of a read-modify-write
560 * to add a new bit for a new object. However, that
561 * RMW will have completed by the time any other thread
562 * could possibly see the new pointer, so there is no
563 * danger of dvmIsValidObject() being called on a valid
564 * pointer whose bit isn't set.
565 *
566 * Freeing will only happen during the sweep phase, which
567 * only happens while the heap is locked.
568 */
Carl Shapiro6343bd02010-02-16 17:40:19 -0800569 return dvmHeapSourceContains(obj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800570 }
571 return false;
572}
573
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800574size_t dvmObjectSizeInHeap(const Object *obj)
575{
Carl Shapiro6343bd02010-02-16 17:40:19 -0800576 return dvmHeapSourceChunkSize(obj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800577}
578
579/*
Barry Hayes962adba2010-03-17 12:12:39 -0700580 * Scan every live object in the heap, holding the locks.
581 */
582static void verifyHeap()
583{
584 // TODO: check the locks.
585 HeapBitmap *liveBits = dvmHeapSourceGetLiveBits();
586 dvmVerifyBitmap(liveBits);
587}
588
589/*
590 * Suspend the VM as for a GC, and assert-fail if any object has any
591 * corrupt references.
592 */
593void dvmHeapSuspendAndVerify()
594{
595 /* Suspend the VM. */
596 dvmSuspendAllThreads(SUSPEND_FOR_VERIFY);
597 dvmLockMutex(&gDvm.heapWorkerLock);
598 dvmAssertHeapWorkerThreadRunning();
599 dvmLockMutex(&gDvm.heapWorkerListLock);
600
601 verifyHeap();
602
603 /* Resume the VM. */
604 dvmUnlockMutex(&gDvm.heapWorkerListLock);
605 dvmUnlockMutex(&gDvm.heapWorkerLock);
606 dvmResumeAllThreads(SUSPEND_FOR_VERIFY);
607}
608
609/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800610 * Initiate garbage collection.
611 *
612 * NOTES:
613 * - If we don't hold gDvm.threadListLock, it's possible for a thread to
614 * be added to the thread list while we work. The thread should NOT
615 * start executing, so this is only interesting when we start chasing
616 * thread stacks. (Before we do so, grab the lock.)
617 *
618 * We are not allowed to GC when the debugger has suspended the VM, which
619 * is awkward because debugger requests can cause allocations. The easiest
620 * way to enforce this is to refuse to GC on an allocation made by the
621 * JDWP thread -- we have to expand the heap or fail.
622 */
Carl Shapiro29540742010-03-26 15:34:39 -0700623void dvmCollectGarbageInternal(bool clearSoftRefs, GcReason reason)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800624{
625 GcHeap *gcHeap = gDvm.gcHeap;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800626 u8 now;
627 s8 timeSinceLastGc;
628 s8 gcElapsedTime;
629 int numFreed;
630 size_t sizeFreed;
Carl Shapirod25566d2010-03-11 20:39:47 -0800631 GcMode gcMode;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800632
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800633 /* The heap lock must be held.
634 */
635
636 if (gcHeap->gcRunning) {
637 LOGW_HEAP("Attempted recursive GC\n");
638 return;
639 }
Carl Shapirod25566d2010-03-11 20:39:47 -0800640 gcMode = (reason == GC_FOR_MALLOC) ? GC_PARTIAL : GC_FULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800641 gcHeap->gcRunning = true;
642 now = dvmGetRelativeTimeUsec();
643 if (gcHeap->gcStartTime != 0) {
644 timeSinceLastGc = (now - gcHeap->gcStartTime) / 1000;
645 } else {
646 timeSinceLastGc = 0;
647 }
648 gcHeap->gcStartTime = now;
649
Barry Hayes1b9b4e42010-01-04 10:33:46 -0800650 LOGV_HEAP("%s starting -- suspending threads\n", GcReasonStr[reason]);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800651
652 dvmSuspendAllThreads(SUSPEND_FOR_GC);
653
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.
657 */
658 errno = 0;
659 int oldThreadPriority = kInvalidPriority;
660 int priorityResult = getpriority(PRIO_PROCESS, 0);
661 if (errno != 0) {
662 LOGI_HEAP("getpriority(self) failed: %s\n", strerror(errno));
663 } else if (priorityResult > ANDROID_PRIORITY_NORMAL) {
664 /* Current value is numerically greater than "normal", which
665 * in backward UNIX terms means lower priority.
666 */
San Mehat256fc152009-04-21 14:03:06 -0700667
San Mehat3e371e22009-06-26 08:36:16 -0700668 if (priorityResult >= ANDROID_PRIORITY_BACKGROUND) {
San Mehat5a2056c2009-09-12 10:10:13 -0700669 set_sched_policy(dvmGetSysThreadId(), SP_FOREGROUND);
San Mehat256fc152009-04-21 14:03:06 -0700670 }
671
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800672 if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL) != 0) {
673 LOGI_HEAP("Unable to elevate priority from %d to %d\n",
674 priorityResult, ANDROID_PRIORITY_NORMAL);
675 } else {
676 /* priority elevated; save value so we can restore it later */
677 LOGD_HEAP("Elevating priority from %d to %d\n",
678 priorityResult, ANDROID_PRIORITY_NORMAL);
679 oldThreadPriority = priorityResult;
680 }
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
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800779 /* Recursively mark any objects that marked objects point to strongly.
780 * If we're not collecting soft references, soft-reachable
781 * objects will also be marked.
782 */
783 LOGD_HEAP("Recursing...");
784 dvmHeapScanMarkedObjects();
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800785
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800786 /* All strongly-reachable objects have now been marked.
787 */
Carl Shapiro29540742010-03-26 15:34:39 -0700788 LOGD_HEAP("Handling soft references...");
789 if (!clearSoftRefs) {
790 dvmHandleSoftRefs(&gcHeap->softReferences);
791 }
792 dvmClearWhiteRefs(&gcHeap->softReferences);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800793
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800794 LOGD_HEAP("Handling weak references...");
Carl Shapiro29540742010-03-26 15:34:39 -0700795 dvmClearWhiteRefs(&gcHeap->weakReferences);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800796
797 /* Once all weak-reachable objects have been taken
798 * care of, any remaining unmarked objects can be finalized.
799 */
800 LOGD_HEAP("Finding finalizations...");
801 dvmHeapScheduleFinalizations();
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800802
Carl Shapiro29540742010-03-26 15:34:39 -0700803 LOGD_HEAP("Handling f-reachable soft references...");
804 dvmClearWhiteRefs(&gcHeap->softReferences);
805
806 LOGD_HEAP("Handling f-reachable weak references...");
807 dvmClearWhiteRefs(&gcHeap->weakReferences);
808
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800809 /* Any remaining objects that are not pending finalization
810 * could be phantom-reachable. This will mark any phantom-reachable
811 * objects, as well as enqueue their references.
812 */
813 LOGD_HEAP("Handling phantom references...");
Carl Shapiro29540742010-03-26 15:34:39 -0700814 dvmClearWhiteRefs(&gcHeap->phantomReferences);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800815
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800816#ifdef WITH_DEADLOCK_PREDICTION
817 dvmDumpMonitorInfo("before sweep");
818#endif
819 LOGD_HEAP("Sweeping...");
Carl Shapirod25566d2010-03-11 20:39:47 -0800820 dvmHeapSweepUnmarkedObjects(gcMode, &numFreed, &sizeFreed);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800821#ifdef WITH_DEADLOCK_PREDICTION
822 dvmDumpMonitorInfo("after sweep");
823#endif
824
825 LOGD_HEAP("Cleaning up...");
826 dvmHeapFinishMarkStep();
827
828 LOGD_HEAP("Done.");
829
830 /* Now's a good time to adjust the heap size, since
831 * we know what our utilization is.
832 *
833 * This doesn't actually resize any memory;
834 * it just lets the heap grow more when necessary.
835 */
836 dvmHeapSourceGrowForUtilization();
837 dvmHeapSizeChanged();
838
839#if WITH_HPROF
840 if (gcHeap->hprofContext != NULL) {
841 hprofFinishHeapDump(gcHeap->hprofContext);
842//TODO: write a HEAP_SUMMARY record
The Android Open Source Project99409882009-03-18 22:20:24 -0700843 if (hprofShutdown(gcHeap->hprofContext))
844 gcHeap->hprofResult = 0; /* indicate success */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800845 gcHeap->hprofContext = NULL;
846 }
847#endif
848
849 /* Now that we've freed up the GC heap, return any large
850 * free chunks back to the system. They'll get paged back
851 * in the next time they're used. Don't do it immediately,
852 * though; if the process is still allocating a bunch of
853 * memory, we'll be taking a ton of page faults that we don't
854 * necessarily need to.
855 *
856 * Cancel any old scheduled trims, and schedule a new one.
857 */
858 dvmScheduleHeapSourceTrim(5); // in seconds
859
860#ifdef WITH_PROFILER
861 dvmMethodTraceGCEnd();
862#endif
Barry Hayes962adba2010-03-17 12:12:39 -0700863 LOGV_HEAP("GC finished");
864
865 if (gDvm.postVerify) {
866 LOGV_HEAP("Verifying heap after GC");
867 verifyHeap();
868 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800869
870 gcHeap->gcRunning = false;
871
Barry Hayes962adba2010-03-17 12:12:39 -0700872 LOGV_HEAP("Resuming threads");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800873 dvmUnlockMutex(&gDvm.heapWorkerListLock);
874 dvmUnlockMutex(&gDvm.heapWorkerLock);
875
Ben Chengc3b92b22010-01-26 16:46:15 -0800876#if defined(WITH_JIT)
Ben Chengc3b92b22010-01-26 16:46:15 -0800877 /*
878 * Patching a chaining cell is very cheap as it only updates 4 words. It's
879 * the overhead of stopping all threads and synchronizing the I/D cache
880 * that makes it expensive.
881 *
882 * Therefore we batch those work orders in a queue and go through them
883 * when threads are suspended for GC.
884 */
885 dvmCompilerPerformSafePointChecks();
886#endif
887
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800888 dvmResumeAllThreads(SUSPEND_FOR_GC);
889 if (oldThreadPriority != kInvalidPriority) {
890 if (setpriority(PRIO_PROCESS, 0, oldThreadPriority) != 0) {
891 LOGW_HEAP("Unable to reset priority to %d: %s\n",
892 oldThreadPriority, strerror(errno));
893 } else {
894 LOGD_HEAP("Reset priority to %d\n", oldThreadPriority);
895 }
San Mehat256fc152009-04-21 14:03:06 -0700896
San Mehat3e371e22009-06-26 08:36:16 -0700897 if (oldThreadPriority >= ANDROID_PRIORITY_BACKGROUND) {
San Mehat5a2056c2009-09-12 10:10:13 -0700898 set_sched_policy(dvmGetSysThreadId(), SP_BACKGROUND);
San Mehat256fc152009-04-21 14:03:06 -0700899 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800900 }
901 gcElapsedTime = (dvmGetRelativeTimeUsec() - gcHeap->gcStartTime) / 1000;
Barry Hayes31364132010-01-04 16:10:09 -0800902 LOGD("%s freed %d objects / %zd bytes in %dms\n",
903 GcReasonStr[reason], numFreed, sizeFreed, (int)gcElapsedTime);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800904 dvmLogGcStats(numFreed, sizeFreed, gcElapsedTime);
905
906 if (gcHeap->ddmHpifWhen != 0) {
907 LOGD_HEAP("Sending VM heap info to DDM\n");
908 dvmDdmSendHeapInfo(gcHeap->ddmHpifWhen, false);
909 }
910 if (gcHeap->ddmHpsgWhen != 0) {
911 LOGD_HEAP("Dumping VM heap to DDM\n");
912 dvmDdmSendHeapSegments(false, false);
913 }
914 if (gcHeap->ddmNhsgWhen != 0) {
915 LOGD_HEAP("Dumping native heap to DDM\n");
916 dvmDdmSendHeapSegments(false, true);
917 }
918}
919
920#if WITH_HPROF
921/*
922 * Perform garbage collection, writing heap information to the specified file.
923 *
924 * If "fileName" is NULL, a suitable name will be generated automatically.
The Android Open Source Project99409882009-03-18 22:20:24 -0700925 *
926 * Returns 0 on success, or an error code on failure.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800927 */
Andy McFadden6bf992c2010-01-28 17:01:39 -0800928int hprofDumpHeap(const char* fileName, bool directToDdms)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800929{
The Android Open Source Project99409882009-03-18 22:20:24 -0700930 int result;
931
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800932 dvmLockMutex(&gDvm.gcHeapLock);
933
934 gDvm.gcHeap->hprofDumpOnGc = true;
935 gDvm.gcHeap->hprofFileName = fileName;
Andy McFadden6bf992c2010-01-28 17:01:39 -0800936 gDvm.gcHeap->hprofDirectToDdms = directToDdms;
Barry Hayes1b9b4e42010-01-04 10:33:46 -0800937 dvmCollectGarbageInternal(false, GC_HPROF_DUMP_HEAP);
The Android Open Source Project99409882009-03-18 22:20:24 -0700938 result = gDvm.gcHeap->hprofResult;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800939
940 dvmUnlockMutex(&gDvm.gcHeapLock);
The Android Open Source Project99409882009-03-18 22:20:24 -0700941
942 return result;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800943}
944
945void dvmHeapSetHprofGcScanState(hprof_heap_tag_t state, u4 threadSerialNumber)
946{
947 if (gDvm.gcHeap->hprofContext != NULL) {
948 hprofSetGcScanState(gDvm.gcHeap->hprofContext, state,
949 threadSerialNumber);
950 }
951}
952#endif