blob: 7e47e738e8a768434019299eb3a17ec67f650e86 [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",
Carl Shapiro07018e22010-10-26 21:07:41 -070043 [GC_EXTERNAL_ALLOC] = "GC_EXTERNAL_ALLOC"
Barry Hayes1b9b4e42010-01-04 10:33:46 -080044};
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
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080055 gcHeap = dvmHeapSourceStartup(gDvm.heapSizeStart, gDvm.heapSizeMax);
56 if (gcHeap == NULL) {
57 return false;
58 }
59 gcHeap->heapWorkerCurrentObject = NULL;
60 gcHeap->heapWorkerCurrentMethod = NULL;
61 gcHeap->heapWorkerInterpStartTime = 0LL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080062 gcHeap->ddmHpifWhen = 0;
63 gcHeap->ddmHpsgWhen = 0;
64 gcHeap->ddmHpsgWhat = 0;
65 gcHeap->ddmNhsgWhen = 0;
66 gcHeap->ddmNhsgWhat = 0;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080067 gDvm.gcHeap = gcHeap;
68
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080069 /* Set up the lists and lock we'll use for finalizable
70 * and reference objects.
71 */
72 dvmInitMutex(&gDvm.heapWorkerListLock);
73 gcHeap->finalizableRefs = NULL;
74 gcHeap->pendingFinalizationRefs = NULL;
75 gcHeap->referenceOperations = NULL;
76
Barry Hayesb874ab92010-07-14 08:13:18 -070077 if (!dvmCardTableStartup()) {
78 LOGE_HEAP("card table startup failed.");
79 return false;
80 }
81
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080082 /* Initialize the HeapWorker locks and other state
83 * that the GC uses.
84 */
85 dvmInitializeHeapWorkerState();
86
87 return true;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080088}
89
Carl Shapiroec805ea2010-06-28 16:28:26 -070090bool dvmHeapStartupAfterZygote(void)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080091{
Carl Shapiroec805ea2010-06-28 16:28:26 -070092 return dvmHeapSourceStartupAfterZygote();
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080093}
94
95void dvmHeapShutdown()
96{
97//TODO: make sure we're locked
98 if (gDvm.gcHeap != NULL) {
Barry Hayesb874ab92010-07-14 08:13:18 -070099 dvmCardTableShutdown();
100 /* Tables are allocated on the native heap; they need to be
101 * cleaned up explicitly. The process may stick around, so we
102 * don't want to leak any native memory.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800103 */
Carl Shapiroa199eb72010-02-09 16:26:30 -0800104 dvmHeapFreeLargeTable(gDvm.gcHeap->finalizableRefs);
105 gDvm.gcHeap->finalizableRefs = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800106
Carl Shapiroa199eb72010-02-09 16:26:30 -0800107 dvmHeapFreeLargeTable(gDvm.gcHeap->pendingFinalizationRefs);
108 gDvm.gcHeap->pendingFinalizationRefs = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800109
Carl Shapiroa199eb72010-02-09 16:26:30 -0800110 dvmHeapFreeLargeTable(gDvm.gcHeap->referenceOperations);
111 gDvm.gcHeap->referenceOperations = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800112
Barry Hayesb874ab92010-07-14 08:13:18 -0700113 /* Destroy the heap. Any outstanding pointers will point to
114 * unmapped memory (unless/until someone else maps it). This
115 * frees gDvm.gcHeap as a side-effect.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800116 */
Carl Shapiroa199eb72010-02-09 16:26:30 -0800117 dvmHeapSourceShutdown(&gDvm.gcHeap);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800118 }
119}
120
121/*
Carl Shapiroec805ea2010-06-28 16:28:26 -0700122 * Shutdown any threads internal to the heap.
123 */
124void dvmHeapThreadShutdown(void)
125{
126 dvmHeapSourceThreadShutdown();
127}
128
129/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800130 * 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();
Carl Shapiro5617ad32010-07-02 10:50:57 -0700159 oldStatus = dvmChangeStatus(self, THREAD_VMWAIT);
Carl Shapiro980ffb02010-03-13 22:34:01 -0800160 dvmLockMutex(&gDvm.gcHeapLock);
Carl Shapiro5617ad32010-07-02 10:50:57 -0700161 dvmChangeStatus(self, oldStatus);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800162 }
163
164 return true;
165}
166
167void dvmUnlockHeap()
168{
169 dvmUnlockMutex(&gDvm.gcHeapLock);
170}
171
172/* Pop an object from the list of pending finalizations and
173 * reference clears/enqueues, and return the object.
174 * The caller must call dvmReleaseTrackedAlloc()
175 * on the object when finished.
176 *
177 * Typically only called by the heap worker thread.
178 */
179Object *dvmGetNextHeapWorkerObject(HeapWorkerOperation *op)
180{
181 Object *obj;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800182 GcHeap *gcHeap = gDvm.gcHeap;
183
184 assert(op != NULL);
185
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800186 dvmLockMutex(&gDvm.heapWorkerListLock);
187
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800188 obj = dvmHeapGetNextObjectFromLargeTable(&gcHeap->referenceOperations);
189 if (obj != NULL) {
Carl Shapiro646ba092010-06-10 15:17:00 -0700190 *op = WORKER_ENQUEUE;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800191 } else {
192 obj = dvmHeapGetNextObjectFromLargeTable(
193 &gcHeap->pendingFinalizationRefs);
194 if (obj != NULL) {
195 *op = WORKER_FINALIZE;
196 }
197 }
198
199 if (obj != NULL) {
200 /* Don't let the GC collect the object until the
201 * worker thread is done with it.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800202 */
203 dvmAddTrackedAlloc(obj, NULL);
204 }
205
206 dvmUnlockMutex(&gDvm.heapWorkerListLock);
207
208 return obj;
209}
210
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800211/* Do a full garbage collection, which may grow the
212 * heap as a side-effect if the live set is large.
213 */
214static void gcForMalloc(bool collectSoftReferences)
215{
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800216 if (gDvm.allocProf.enabled) {
217 Thread* self = dvmThreadSelf();
218 gDvm.allocProf.gcCount++;
219 if (self != NULL) {
220 self->allocProf.gcCount++;
221 }
222 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800223 /* This may adjust the soft limit as a side-effect.
224 */
225 LOGD_HEAP("dvmMalloc initiating GC%s\n",
226 collectSoftReferences ? "(collect SoftReferences)" : "");
Barry Hayes1b9b4e42010-01-04 10:33:46 -0800227 dvmCollectGarbageInternal(collectSoftReferences, GC_FOR_MALLOC);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800228}
229
230/* Try as hard as possible to allocate some memory.
231 */
Carl Shapiro6343bd02010-02-16 17:40:19 -0800232static void *tryMalloc(size_t size)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800233{
Carl Shapiro6343bd02010-02-16 17:40:19 -0800234 void *ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800235
236 /* Don't try too hard if there's no way the allocation is
237 * going to succeed. We have to collect SoftReferences before
238 * throwing an OOME, though.
239 */
240 if (size >= gDvm.heapSizeMax) {
241 LOGW_HEAP("dvmMalloc(%zu/0x%08zx): "
242 "someone's allocating a huge buffer\n", size, size);
Carl Shapiro6343bd02010-02-16 17:40:19 -0800243 ptr = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800244 goto collect_soft_refs;
245 }
246
247//TODO: figure out better heuristics
248// There will be a lot of churn if someone allocates a bunch of
249// big objects in a row, and we hit the frag case each time.
250// A full GC for each.
251// Maybe we grow the heap in bigger leaps
252// Maybe we skip the GC if the size is large and we did one recently
253// (number of allocations ago) (watch for thread effects)
254// DeflateTest allocs a bunch of ~128k buffers w/in 0-5 allocs of each other
255// (or, at least, there are only 0-5 objects swept each time)
256
Carl Shapiro6343bd02010-02-16 17:40:19 -0800257 ptr = dvmHeapSourceAlloc(size);
258 if (ptr != NULL) {
259 return ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800260 }
261
Carl Shapiroec47e2e2010-07-01 17:44:46 -0700262 /*
263 * The allocation failed. If the GC is running, block until it
264 * completes and retry.
265 */
266 if (gDvm.gcHeap->gcRunning) {
267 /*
268 * The GC is concurrently tracing the heap. Release the heap
269 * lock, wait for the GC to complete, and retrying allocating.
270 */
271 dvmWaitForConcurrentGcToComplete();
272 ptr = dvmHeapSourceAlloc(size);
273 if (ptr != NULL) {
274 return ptr;
275 }
276 }
277 /*
278 * Another failure. Our thread was starved or there may be too
279 * many live objects. Try a foreground GC. This will have no
280 * effect if the concurrent GC is already running.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800281 */
282 gcForMalloc(false);
Carl Shapiro6343bd02010-02-16 17:40:19 -0800283 ptr = dvmHeapSourceAlloc(size);
284 if (ptr != NULL) {
285 return ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800286 }
287
288 /* Even that didn't work; this is an exceptional state.
289 * Try harder, growing the heap if necessary.
290 */
Carl Shapiro6343bd02010-02-16 17:40:19 -0800291 ptr = dvmHeapSourceAllocAndGrow(size);
Carl Shapiro6343bd02010-02-16 17:40:19 -0800292 if (ptr != NULL) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800293 size_t newHeapSize;
294
295 newHeapSize = dvmHeapSourceGetIdealFootprint();
296//TODO: may want to grow a little bit more so that the amount of free
297// space is equal to the old free space + the utilization slop for
298// the new allocation.
299 LOGI_HEAP("Grow heap (frag case) to "
300 "%zu.%03zuMB for %zu-byte allocation\n",
301 FRACTIONAL_MB(newHeapSize), size);
Carl Shapiro6343bd02010-02-16 17:40:19 -0800302 return ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800303 }
304
305 /* Most allocations should have succeeded by now, so the heap
306 * is really full, really fragmented, or the requested size is
307 * really big. Do another GC, collecting SoftReferences this
308 * time. The VM spec requires that all SoftReferences have
309 * been collected and cleared before throwing an OOME.
310 */
311//TODO: wait for the finalizers from the previous GC to finish
312collect_soft_refs:
313 LOGI_HEAP("Forcing collection of SoftReferences for %zu-byte allocation\n",
314 size);
315 gcForMalloc(true);
Carl Shapiro6343bd02010-02-16 17:40:19 -0800316 ptr = dvmHeapSourceAllocAndGrow(size);
Carl Shapiro6343bd02010-02-16 17:40:19 -0800317 if (ptr != NULL) {
318 return ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800319 }
320//TODO: maybe wait for finalizers and try one last time
321
322 LOGE_HEAP("Out of memory on a %zd-byte allocation.\n", size);
323//TODO: tell the HeapSource to dump its state
324 dvmDumpThread(dvmThreadSelf(), false);
325
326 return NULL;
327}
328
329/* Throw an OutOfMemoryError if there's a thread to attach it to.
330 * Avoid recursing.
331 *
332 * The caller must not be holding the heap lock, or else the allocations
333 * in dvmThrowException() will deadlock.
334 */
335static void throwOOME()
336{
337 Thread *self;
338
339 if ((self = dvmThreadSelf()) != NULL) {
340 /* If the current (failing) dvmMalloc() happened as part of thread
341 * creation/attachment before the thread became part of the root set,
342 * we can't rely on the thread-local trackedAlloc table, so
343 * we can't keep track of a real allocated OOME object. But, since
344 * the thread is in the process of being created, it won't have
345 * a useful stack anyway, so we may as well make things easier
346 * by throwing the (stackless) pre-built OOME.
347 */
348 if (dvmIsOnThreadList(self) && !self->throwingOOME) {
349 /* Let ourselves know that we tried to throw an OOM
350 * error in the normal way in case we run out of
351 * memory trying to allocate it inside dvmThrowException().
352 */
353 self->throwingOOME = true;
354
355 /* Don't include a description string;
356 * one fewer allocation.
357 */
358 dvmThrowException("Ljava/lang/OutOfMemoryError;", NULL);
359 } else {
360 /*
361 * This thread has already tried to throw an OutOfMemoryError,
362 * which probably means that we're running out of memory
363 * while recursively trying to throw.
364 *
365 * To avoid any more allocation attempts, "throw" a pre-built
366 * OutOfMemoryError object (which won't have a useful stack trace).
367 *
368 * Note that since this call can't possibly allocate anything,
369 * we don't care about the state of self->throwingOOME
370 * (which will usually already be set).
371 */
372 dvmSetException(self, gDvm.outOfMemoryObj);
373 }
374 /* We're done with the possible recursion.
375 */
376 self->throwingOOME = false;
377 }
378}
379
380/*
381 * Allocate storage on the GC heap. We guarantee 8-byte alignment.
382 *
383 * The new storage is zeroed out.
384 *
385 * Note that, in rare cases, this could get called while a GC is in
386 * progress. If a non-VM thread tries to attach itself through JNI,
387 * it will need to allocate some objects. If this becomes annoying to
388 * deal with, we can block it at the source, but holding the allocation
389 * mutex should be enough.
390 *
391 * In rare circumstances (JNI AttachCurrentThread) we can be called
392 * from a non-VM thread.
393 *
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800394 * Use ALLOC_DONT_TRACK when we either don't want to track an allocation
395 * (because it's being done for the interpreter "new" operation and will
396 * be part of the root set immediately) or we can't (because this allocation
397 * is for a brand new thread).
398 *
399 * Returns NULL and throws an exception on failure.
400 *
401 * TODO: don't do a GC if the debugger thinks all threads are suspended
402 */
403void* dvmMalloc(size_t size, int flags)
404{
405 GcHeap *gcHeap = gDvm.gcHeap;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800406 void *ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800407
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800408 dvmLockHeap();
409
410 /* Try as hard as possible to allocate some memory.
411 */
Carl Shapiro6343bd02010-02-16 17:40:19 -0800412 ptr = tryMalloc(size);
413 if (ptr != NULL) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800414 /* We've got the memory.
415 */
416 if ((flags & ALLOC_FINALIZABLE) != 0) {
417 /* This object is an instance of a class that
418 * overrides finalize(). Add it to the finalizable list.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800419 */
420 if (!dvmHeapAddRefToLargeTable(&gcHeap->finalizableRefs,
Carl Shapiro6343bd02010-02-16 17:40:19 -0800421 (Object *)ptr))
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800422 {
423 LOGE_HEAP("dvmMalloc(): no room for any more "
424 "finalizable objects\n");
425 dvmAbort();
426 }
427 }
428
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800429 if (gDvm.allocProf.enabled) {
430 Thread* self = dvmThreadSelf();
431 gDvm.allocProf.allocCount++;
432 gDvm.allocProf.allocSize += size;
433 if (self != NULL) {
434 self->allocProf.allocCount++;
435 self->allocProf.allocSize += size;
436 }
437 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800438 } else {
439 /* The allocation failed.
440 */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800441
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800442 if (gDvm.allocProf.enabled) {
443 Thread* self = dvmThreadSelf();
444 gDvm.allocProf.failedAllocCount++;
445 gDvm.allocProf.failedAllocSize += size;
446 if (self != NULL) {
447 self->allocProf.failedAllocCount++;
448 self->allocProf.failedAllocSize += size;
449 }
450 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800451 }
452
453 dvmUnlockHeap();
454
455 if (ptr != NULL) {
456 /*
Barry Hayesd4f78d32010-06-08 09:34:42 -0700457 * If caller hasn't asked us not to track it, add it to the
458 * internal tracking list.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800459 */
Barry Hayesd4f78d32010-06-08 09:34:42 -0700460 if ((flags & ALLOC_DONT_TRACK) == 0) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800461 dvmAddTrackedAlloc(ptr, NULL);
462 }
463 } else {
Ben Chengc3b92b22010-01-26 16:46:15 -0800464 /*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800465 * The allocation failed; throw an OutOfMemoryError.
466 */
467 throwOOME();
468 }
469
470 return ptr;
471}
472
473/*
474 * Returns true iff <obj> points to a valid allocated object.
475 */
476bool dvmIsValidObject(const Object* obj)
477{
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800478 /* Don't bother if it's NULL or not 8-byte aligned.
479 */
Carl Shapiro6343bd02010-02-16 17:40:19 -0800480 if (obj != NULL && ((uintptr_t)obj & (8-1)) == 0) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800481 /* Even if the heap isn't locked, this shouldn't return
482 * any false negatives. The only mutation that could
483 * be happening is allocation, which means that another
484 * thread could be in the middle of a read-modify-write
485 * to add a new bit for a new object. However, that
486 * RMW will have completed by the time any other thread
487 * could possibly see the new pointer, so there is no
488 * danger of dvmIsValidObject() being called on a valid
489 * pointer whose bit isn't set.
490 *
491 * Freeing will only happen during the sweep phase, which
492 * only happens while the heap is locked.
493 */
Carl Shapiro6343bd02010-02-16 17:40:19 -0800494 return dvmHeapSourceContains(obj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800495 }
496 return false;
497}
498
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800499size_t dvmObjectSizeInHeap(const Object *obj)
500{
Carl Shapiro6343bd02010-02-16 17:40:19 -0800501 return dvmHeapSourceChunkSize(obj);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800502}
503
Carl Shapiro6c5dd932010-08-05 21:49:07 -0700504static void verifyRootsAndHeap(void)
Barry Hayes962adba2010-03-17 12:12:39 -0700505{
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700506 dvmVerifyRoots();
507 dvmVerifyBitmap(dvmHeapSourceGetLiveBits());
Barry Hayes962adba2010-03-17 12:12:39 -0700508}
509
510/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800511 * Initiate garbage collection.
512 *
513 * NOTES:
514 * - If we don't hold gDvm.threadListLock, it's possible for a thread to
515 * be added to the thread list while we work. The thread should NOT
516 * start executing, so this is only interesting when we start chasing
517 * thread stacks. (Before we do so, grab the lock.)
518 *
519 * We are not allowed to GC when the debugger has suspended the VM, which
520 * is awkward because debugger requests can cause allocations. The easiest
521 * way to enforce this is to refuse to GC on an allocation made by the
522 * JDWP thread -- we have to expand the heap or fail.
523 */
Carl Shapiro29540742010-03-26 15:34:39 -0700524void dvmCollectGarbageInternal(bool clearSoftRefs, GcReason reason)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800525{
526 GcHeap *gcHeap = gDvm.gcHeap;
Carl Shapiro8881a802010-08-10 15:55:45 -0700527 u4 rootSuspend, rootSuspendTime, rootStart, rootEnd;
528 u4 dirtySuspend, dirtyStart, dirtyEnd;
529 u4 totalTime;
Carl Shapiro570942c2010-09-17 15:53:16 -0700530 size_t numObjectsFreed, numBytesFreed;
531 size_t currAllocated, currFootprint;
532 size_t extAllocated, extLimit;
533 size_t percentFree;
Carl Shapirod25566d2010-03-11 20:39:47 -0800534 GcMode gcMode;
Carl Shapiroec805ea2010-06-28 16:28:26 -0700535 int oldThreadPriority = kInvalidPriority;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800536
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800537 /* The heap lock must be held.
538 */
539
540 if (gcHeap->gcRunning) {
541 LOGW_HEAP("Attempted recursive GC\n");
542 return;
543 }
Carl Shapiro03f3b132010-07-27 17:25:31 -0700544
Carl Shapirod25566d2010-03-11 20:39:47 -0800545 gcMode = (reason == GC_FOR_MALLOC) ? GC_PARTIAL : GC_FULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800546 gcHeap->gcRunning = true;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800547
Carl Shapiro8881a802010-08-10 15:55:45 -0700548 rootSuspend = dvmGetRelativeTimeMsec();
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800549 dvmSuspendAllThreads(SUSPEND_FOR_GC);
Carl Shapiro03f3b132010-07-27 17:25:31 -0700550 rootStart = dvmGetRelativeTimeMsec();
Carl Shapiro8881a802010-08-10 15:55:45 -0700551 rootSuspendTime = rootStart - rootSuspend;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800552
Carl Shapiroec805ea2010-06-28 16:28:26 -0700553 /*
554 * If we are not marking concurrently raise the priority of the
555 * thread performing the garbage collection.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800556 */
Carl Shapiroec805ea2010-06-28 16:28:26 -0700557 if (reason != GC_CONCURRENT) {
558 /* Get the priority (the "nice" value) of the current thread. The
559 * getpriority() call can legitimately return -1, so we have to
560 * explicitly test errno.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800561 */
Carl Shapiroec805ea2010-06-28 16:28:26 -0700562 errno = 0;
563 int priorityResult = getpriority(PRIO_PROCESS, 0);
564 if (errno != 0) {
565 LOGI_HEAP("getpriority(self) failed: %s\n", strerror(errno));
566 } else if (priorityResult > ANDROID_PRIORITY_NORMAL) {
567 /* Current value is numerically greater than "normal", which
568 * in backward UNIX terms means lower priority.
569 */
San Mehat256fc152009-04-21 14:03:06 -0700570
Carl Shapiroec805ea2010-06-28 16:28:26 -0700571 if (priorityResult >= ANDROID_PRIORITY_BACKGROUND) {
572 set_sched_policy(dvmGetSysThreadId(), SP_FOREGROUND);
573 }
San Mehat256fc152009-04-21 14:03:06 -0700574
Carl Shapiroec805ea2010-06-28 16:28:26 -0700575 if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL) != 0) {
576 LOGI_HEAP("Unable to elevate priority from %d to %d\n",
577 priorityResult, ANDROID_PRIORITY_NORMAL);
578 } else {
579 /* priority elevated; save value so we can restore it later */
580 LOGD_HEAP("Elevating priority from %d to %d\n",
581 priorityResult, ANDROID_PRIORITY_NORMAL);
582 oldThreadPriority = priorityResult;
583 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800584 }
585 }
586
587 /* Wait for the HeapWorker thread to block.
588 * (It may also already be suspended in interp code,
589 * in which case it's not holding heapWorkerLock.)
590 */
591 dvmLockMutex(&gDvm.heapWorkerLock);
592
593 /* Make sure that the HeapWorker thread hasn't become
594 * wedged inside interp code. If it has, this call will
595 * print a message and abort the VM.
596 */
597 dvmAssertHeapWorkerThreadRunning();
598
599 /* Lock the pendingFinalizationRefs list.
600 *
601 * Acquire the lock after suspending so the finalizer
602 * thread can't block in the RUNNING state while
603 * we try to suspend.
604 */
605 dvmLockMutex(&gDvm.heapWorkerListLock);
606
Barry Hayes962adba2010-03-17 12:12:39 -0700607 if (gDvm.preVerify) {
Carl Shapiro6c5dd932010-08-05 21:49:07 -0700608 LOGV_HEAP("Verifying roots and heap before GC");
609 verifyRootsAndHeap();
Barry Hayes962adba2010-03-17 12:12:39 -0700610 }
611
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800612 dvmMethodTraceGCBegin();
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800613
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800614 /* Set up the marking context.
615 */
Carl Shapirod25566d2010-03-11 20:39:47 -0800616 if (!dvmHeapBeginMarkStep(gcMode)) {
The Android Open Source Project99409882009-03-18 22:20:24 -0700617 LOGE_HEAP("dvmHeapBeginMarkStep failed; aborting\n");
618 dvmAbort();
619 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800620
621 /* Mark the set of objects that are strongly reachable from the roots.
622 */
623 LOGD_HEAP("Marking...");
624 dvmHeapMarkRootSet();
625
626 /* dvmHeapScanMarkedObjects() will build the lists of known
627 * instances of the Reference classes.
628 */
629 gcHeap->softReferences = NULL;
630 gcHeap->weakReferences = NULL;
631 gcHeap->phantomReferences = NULL;
632
Carl Shapiroec805ea2010-06-28 16:28:26 -0700633 if (reason == GC_CONCURRENT) {
634 /*
Carl Shapiroec47e2e2010-07-01 17:44:46 -0700635 * Resume threads while tracing from the roots. We unlock the
636 * heap to allow mutator threads to allocate from free space.
Carl Shapiroec805ea2010-06-28 16:28:26 -0700637 */
Carl Shapiro03f3b132010-07-27 17:25:31 -0700638 rootEnd = dvmGetRelativeTimeMsec();
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700639 dvmClearCardTable();
Carl Shapiroec47e2e2010-07-01 17:44:46 -0700640 dvmUnlockHeap();
Carl Shapiroec805ea2010-06-28 16:28:26 -0700641 dvmResumeAllThreads(SUSPEND_FOR_GC);
642 }
643
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800644 /* Recursively mark any objects that marked objects point to strongly.
645 * If we're not collecting soft references, soft-reachable
646 * objects will also be marked.
647 */
648 LOGD_HEAP("Recursing...");
649 dvmHeapScanMarkedObjects();
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800650
Carl Shapiroec805ea2010-06-28 16:28:26 -0700651 if (reason == GC_CONCURRENT) {
652 /*
Carl Shapiroec47e2e2010-07-01 17:44:46 -0700653 * Re-acquire the heap lock and perform the final thread
654 * suspension.
Carl Shapiroec805ea2010-06-28 16:28:26 -0700655 */
Carl Shapiroec47e2e2010-07-01 17:44:46 -0700656 dvmLockHeap();
Carl Shapiro8881a802010-08-10 15:55:45 -0700657 dirtySuspend = dvmGetRelativeTimeMsec();
Carl Shapiroec805ea2010-06-28 16:28:26 -0700658 dvmSuspendAllThreads(SUSPEND_FOR_GC);
Carl Shapiro03f3b132010-07-27 17:25:31 -0700659 dirtyStart = dvmGetRelativeTimeMsec();
Carl Shapiroec805ea2010-06-28 16:28:26 -0700660 /*
661 * As no barrier intercepts root updates, we conservatively
662 * assume all roots may be gray and re-mark them.
663 */
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700664 dvmHeapReMarkRootSet();
Carl Shapiroec805ea2010-06-28 16:28:26 -0700665 /*
Carl Shapiro5ba39372010-08-06 17:07:53 -0700666 * With the exception of reference objects and weak interned
667 * strings, all gray objects should now be on dirty cards.
668 */
669 if (gDvm.verifyCardTable) {
670 dvmVerifyCardTable();
671 }
672 /*
Carl Shapiroec805ea2010-06-28 16:28:26 -0700673 * Recursively mark gray objects pointed to by the roots or by
674 * heap objects dirtied during the concurrent mark.
675 */
Carl Shapiro106c5fd2010-07-28 14:12:27 -0700676 dvmHeapReScanMarkedObjects();
Carl Shapiroec805ea2010-06-28 16:28:26 -0700677 }
678
Carl Shapiroe8ef2b52010-12-01 19:32:05 -0800679 /*
680 * All strongly-reachable objects have now been marked. Process
681 * weakly-reachable objects discovered while tracing.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800682 */
Carl Shapiroe8ef2b52010-12-01 19:32:05 -0800683 dvmHeapProcessReferences(&gcHeap->softReferences, clearSoftRefs,
684 &gcHeap->weakReferences,
685 &gcHeap->phantomReferences);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800686
Carl Shapiro8881a802010-08-10 15:55:45 -0700687#if defined(WITH_JIT)
688 /*
689 * Patching a chaining cell is very cheap as it only updates 4 words. It's
690 * the overhead of stopping all threads and synchronizing the I/D cache
691 * that makes it expensive.
692 *
693 * Therefore we batch those work orders in a queue and go through them
694 * when threads are suspended for GC.
695 */
696 dvmCompilerPerformSafePointChecks();
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800697#endif
698
Carl Shapiro8881a802010-08-10 15:55:45 -0700699 LOGD_HEAP("Sweeping...");
700
701 dvmHeapSweepSystemWeaks();
702
703 /*
704 * Live objects have a bit set in the mark bitmap, swap the mark
705 * and live bitmaps. The sweep can proceed concurrently viewing
706 * the new live bitmap as the old mark bitmap, and vice versa.
707 */
708 dvmHeapSourceSwapBitmaps();
709
710 if (gDvm.postVerify) {
711 LOGV_HEAP("Verifying roots and heap after GC");
712 verifyRootsAndHeap();
713 }
714
715 if (reason == GC_CONCURRENT) {
716 dirtyEnd = dvmGetRelativeTimeMsec();
717 dvmUnlockHeap();
718 dvmResumeAllThreads(SUSPEND_FOR_GC);
719 }
720 dvmHeapSweepUnmarkedObjects(gcMode, reason == GC_CONCURRENT,
Carl Shapiro570942c2010-09-17 15:53:16 -0700721 &numObjectsFreed, &numBytesFreed);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800722 LOGD_HEAP("Cleaning up...");
723 dvmHeapFinishMarkStep();
Carl Shapiro8881a802010-08-10 15:55:45 -0700724 if (reason == GC_CONCURRENT) {
725 dvmLockHeap();
726 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800727
728 LOGD_HEAP("Done.");
729
730 /* Now's a good time to adjust the heap size, since
731 * we know what our utilization is.
732 *
733 * This doesn't actually resize any memory;
734 * it just lets the heap grow more when necessary.
735 */
Carl Shapirob755f9a2010-09-27 17:25:49 -0700736 if (reason != GC_EXTERNAL_ALLOC) {
737 dvmHeapSourceGrowForUtilization();
738 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800739
Carl Shapiro570942c2010-09-17 15:53:16 -0700740 currAllocated = dvmHeapSourceGetValue(HS_BYTES_ALLOCATED, NULL, 0);
741 currFootprint = dvmHeapSourceGetValue(HS_FOOTPRINT, NULL, 0);
742
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800743 /* Now that we've freed up the GC heap, return any large
744 * free chunks back to the system. They'll get paged back
745 * in the next time they're used. Don't do it immediately,
746 * though; if the process is still allocating a bunch of
747 * memory, we'll be taking a ton of page faults that we don't
748 * necessarily need to.
749 *
750 * Cancel any old scheduled trims, and schedule a new one.
751 */
752 dvmScheduleHeapSourceTrim(5); // in seconds
753
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800754 dvmMethodTraceGCEnd();
Barry Hayes962adba2010-03-17 12:12:39 -0700755 LOGV_HEAP("GC finished");
756
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800757 gcHeap->gcRunning = false;
758
Barry Hayes962adba2010-03-17 12:12:39 -0700759 LOGV_HEAP("Resuming threads");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800760 dvmUnlockMutex(&gDvm.heapWorkerListLock);
761 dvmUnlockMutex(&gDvm.heapWorkerLock);
762
Carl Shapiroec47e2e2010-07-01 17:44:46 -0700763 if (reason == GC_CONCURRENT) {
764 /*
765 * Wake-up any threads that blocked after a failed allocation
766 * request.
767 */
768 dvmBroadcastCond(&gDvm.gcHeapCond);
769 }
770
Carl Shapiroec805ea2010-06-28 16:28:26 -0700771 if (reason != GC_CONCURRENT) {
Carl Shapiro8881a802010-08-10 15:55:45 -0700772 dirtyEnd = dvmGetRelativeTimeMsec();
773 dvmResumeAllThreads(SUSPEND_FOR_GC);
Carl Shapiroec805ea2010-06-28 16:28:26 -0700774 if (oldThreadPriority != kInvalidPriority) {
775 if (setpriority(PRIO_PROCESS, 0, oldThreadPriority) != 0) {
776 LOGW_HEAP("Unable to reset priority to %d: %s\n",
777 oldThreadPriority, strerror(errno));
778 } else {
779 LOGD_HEAP("Reset priority to %d\n", oldThreadPriority);
780 }
San Mehat256fc152009-04-21 14:03:06 -0700781
Carl Shapiroec805ea2010-06-28 16:28:26 -0700782 if (oldThreadPriority >= ANDROID_PRIORITY_BACKGROUND) {
783 set_sched_policy(dvmGetSysThreadId(), SP_BACKGROUND);
784 }
San Mehat256fc152009-04-21 14:03:06 -0700785 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800786 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800787
Carl Shapiro570942c2010-09-17 15:53:16 -0700788 extAllocated = dvmHeapSourceGetValue(HS_EXTERNAL_BYTES_ALLOCATED, NULL, 0);
789 extLimit = dvmHeapSourceGetValue(HS_EXTERNAL_LIMIT, NULL, 0);
790 percentFree = 100 - (size_t)(100.0f * (float)currAllocated / currFootprint);
Carl Shapiro03f3b132010-07-27 17:25:31 -0700791 if (reason != GC_CONCURRENT) {
Carl Shapiro03f3b132010-07-27 17:25:31 -0700792 u4 markSweepTime = dirtyEnd - rootStart;
Carl Shapiro570942c2010-09-17 15:53:16 -0700793 bool isSmall = numBytesFreed > 0 && numBytesFreed < 1024;
Carl Shapiro8881a802010-08-10 15:55:45 -0700794 totalTime = rootSuspendTime + markSweepTime;
Carl Shapiro71978ec2010-09-21 13:28:21 -0700795 LOGD("%s freed %s%zdK, %d%% free %zdK/%zdK, external %zdK/%zdK, "
Carl Shapiro570942c2010-09-17 15:53:16 -0700796 "paused %ums",
797 GcReasonStr[reason],
798 isSmall ? "<" : "",
799 numBytesFreed ? MAX(numBytesFreed / 1024, 1) : 0,
800 percentFree,
801 currAllocated / 1024, currFootprint / 1024,
802 extAllocated / 1024, extLimit / 1024,
803 markSweepTime);
Carl Shapiro03f3b132010-07-27 17:25:31 -0700804 } else {
Carl Shapiro8881a802010-08-10 15:55:45 -0700805 u4 rootTime = rootEnd - rootStart;
806 u4 dirtySuspendTime = dirtyStart - dirtySuspend;
807 u4 dirtyTime = dirtyEnd - dirtyStart;
Carl Shapiro570942c2010-09-17 15:53:16 -0700808 bool isSmall = numBytesFreed > 0 && numBytesFreed < 1024;
Carl Shapiro03f3b132010-07-27 17:25:31 -0700809 totalTime = rootSuspendTime + rootTime + dirtySuspendTime + dirtyTime;
Carl Shapiro71978ec2010-09-21 13:28:21 -0700810 LOGD("%s freed %s%zdK, %d%% free %zdK/%zdK, external %zdK/%zdK, "
Carl Shapiro570942c2010-09-17 15:53:16 -0700811 "paused %ums+%ums",
812 GcReasonStr[reason],
813 isSmall ? "<" : "",
814 numBytesFreed ? MAX(numBytesFreed / 1024, 1) : 0,
815 percentFree,
816 currAllocated / 1024, currFootprint / 1024,
817 extAllocated / 1024, extLimit / 1024,
818 rootTime, dirtyTime);
Carl Shapiro03f3b132010-07-27 17:25:31 -0700819 }
Carl Shapiro570942c2010-09-17 15:53:16 -0700820 dvmLogGcStats(numObjectsFreed, numBytesFreed, totalTime);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800821 if (gcHeap->ddmHpifWhen != 0) {
822 LOGD_HEAP("Sending VM heap info to DDM\n");
823 dvmDdmSendHeapInfo(gcHeap->ddmHpifWhen, false);
824 }
825 if (gcHeap->ddmHpsgWhen != 0) {
826 LOGD_HEAP("Dumping VM heap to DDM\n");
827 dvmDdmSendHeapSegments(false, false);
828 }
829 if (gcHeap->ddmNhsgWhen != 0) {
830 LOGD_HEAP("Dumping native heap to DDM\n");
831 dvmDdmSendHeapSegments(false, true);
832 }
833}
834
Carl Shapiroec47e2e2010-07-01 17:44:46 -0700835void dvmWaitForConcurrentGcToComplete(void)
836{
837 Thread *self = dvmThreadSelf();
838 ThreadStatus oldStatus;
839 assert(self != NULL);
840 oldStatus = dvmChangeStatus(self, THREAD_VMWAIT);
841 dvmWaitCond(&gDvm.gcHeapCond, &gDvm.gcHeapLock);
842 dvmChangeStatus(self, oldStatus);
843}