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