1f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
2f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
3f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
4f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * you may not use this file except in compliance with the License.
6f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * You may obtain a copy of the License at
7f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
8f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
10f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * See the License for the specific language governing permissions and
14f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * limitations under the License.
15f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
16f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
17f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Garbage-collecting memory allocator.
18f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
19f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include "Dalvik.h"
20962adba4e5db286a36bc8024f5c023bcf6f29312Barry Hayes#include "alloc/HeapBitmap.h"
21962adba4e5db286a36bc8024f5c023bcf6f29312Barry Hayes#include "alloc/Verify.h"
22f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include "alloc/HeapTable.h"
23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include "alloc/Heap.h"
24f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include "alloc/HeapInternal.h"
25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include "alloc/DdmHeap.h"
26f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include "alloc/HeapSource.h"
27f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include "alloc/MarkSweep.h"
28106c5fd9745a47d663e28217f3dd5ac48f606f81Carl Shapiro#include "alloc/Visit.h"
29f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
30f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include "utils/threads.h"      // need Android thread priorities
31f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#define kInvalidPriority        10000
32f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
335a2056ca8c7e7c0ed9f51d68cedbee59cc936685San Mehat#include <cutils/sched_policy.h>
345a2056ca8c7e7c0ed9f51d68cedbee59cc936685San Mehat
35f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include <sys/time.h>
36f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include <sys/resource.h>
37f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include <limits.h>
38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include <errno.h>
39f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
401b9b4e4b89e1c682b6684ae5e2a637e4497a67e9Barry Hayesstatic const char* GcReasonStr[] = {
411b9b4e4b89e1c682b6684ae5e2a637e4497a67e9Barry Hayes    [GC_FOR_MALLOC] = "GC_FOR_MALLOC",
42ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro    [GC_CONCURRENT] = "GC_CONCURRENT",
431b9b4e4b89e1c682b6684ae5e2a637e4497a67e9Barry Hayes    [GC_EXPLICIT] = "GC_EXPLICIT",
441b9b4e4b89e1c682b6684ae5e2a637e4497a67e9Barry Hayes    [GC_EXTERNAL_ALLOC] = "GC_EXTERNAL_ALLOC",
451b9b4e4b89e1c682b6684ae5e2a637e4497a67e9Barry Hayes    [GC_HPROF_DUMP_HEAP] = "GC_HPROF_DUMP_HEAP"
461b9b4e4b89e1c682b6684ae5e2a637e4497a67e9Barry Hayes};
471b9b4e4b89e1c682b6684ae5e2a637e4497a67e9Barry Hayes
48f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
49f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Initialize the GC heap.
50f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
51f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Returns true if successful, false otherwise.
52f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
53f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbool dvmHeapStartup()
54f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
55f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    GcHeap *gcHeap;
56f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
57f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#if defined(WITH_ALLOC_LIMITS)
58f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gDvm.checkAllocLimits = false;
59f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gDvm.allocationLimit = -1;
60f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#endif
61f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
62f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gcHeap = dvmHeapSourceStartup(gDvm.heapSizeStart, gDvm.heapSizeMax);
63f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (gcHeap == NULL) {
64f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return false;
65f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
66f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gcHeap->heapWorkerCurrentObject = NULL;
67f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gcHeap->heapWorkerCurrentMethod = NULL;
68f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gcHeap->heapWorkerInterpStartTime = 0LL;
69f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gcHeap->ddmHpifWhen = 0;
70f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gcHeap->ddmHpsgWhen = 0;
71f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gcHeap->ddmHpsgWhat = 0;
72f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gcHeap->ddmNhsgWhen = 0;
73f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gcHeap->ddmNhsgWhat = 0;
74f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#if WITH_HPROF
75f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gcHeap->hprofDumpOnGc = false;
76f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gcHeap->hprofContext = NULL;
77f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#endif
78f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gDvm.gcHeap = gcHeap;
79f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
80f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* Set up the lists and lock we'll use for finalizable
81f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * and reference objects.
82f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
83f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmInitMutex(&gDvm.heapWorkerListLock);
84f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gcHeap->finalizableRefs = NULL;
85f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gcHeap->pendingFinalizationRefs = NULL;
86f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gcHeap->referenceOperations = NULL;
87f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
88b874ab98306a109c4988bb1cde687a24f4f8201fBarry Hayes    if (!dvmCardTableStartup()) {
89b874ab98306a109c4988bb1cde687a24f4f8201fBarry Hayes        LOGE_HEAP("card table startup failed.");
90b874ab98306a109c4988bb1cde687a24f4f8201fBarry Hayes        return false;
91b874ab98306a109c4988bb1cde687a24f4f8201fBarry Hayes    }
92b874ab98306a109c4988bb1cde687a24f4f8201fBarry Hayes
93f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* Initialize the HeapWorker locks and other state
94f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * that the GC uses.
95f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
96f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmInitializeHeapWorkerState();
97f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
98f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return true;
99f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
101ec805eaed940e40212e85b58b163c7649feaca56Carl Shapirobool dvmHeapStartupAfterZygote(void)
102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
103ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro    return dvmHeapSourceStartupAfterZygote();
104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid dvmHeapShutdown()
107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project//TODO: make sure we're locked
109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (gDvm.gcHeap != NULL) {
110b874ab98306a109c4988bb1cde687a24f4f8201fBarry Hayes        dvmCardTableShutdown();
111b874ab98306a109c4988bb1cde687a24f4f8201fBarry Hayes         /* Tables are allocated on the native heap; they need to be
112b874ab98306a109c4988bb1cde687a24f4f8201fBarry Hayes         * cleaned up explicitly.  The process may stick around, so we
113b874ab98306a109c4988bb1cde687a24f4f8201fBarry Hayes         * don't want to leak any native memory.
114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
115a199eb70871a8c142a723d76b1b08939286a3199Carl Shapiro        dvmHeapFreeLargeTable(gDvm.gcHeap->finalizableRefs);
116a199eb70871a8c142a723d76b1b08939286a3199Carl Shapiro        gDvm.gcHeap->finalizableRefs = NULL;
117f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
118a199eb70871a8c142a723d76b1b08939286a3199Carl Shapiro        dvmHeapFreeLargeTable(gDvm.gcHeap->pendingFinalizationRefs);
119a199eb70871a8c142a723d76b1b08939286a3199Carl Shapiro        gDvm.gcHeap->pendingFinalizationRefs = NULL;
120f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
121a199eb70871a8c142a723d76b1b08939286a3199Carl Shapiro        dvmHeapFreeLargeTable(gDvm.gcHeap->referenceOperations);
122a199eb70871a8c142a723d76b1b08939286a3199Carl Shapiro        gDvm.gcHeap->referenceOperations = NULL;
123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
124b874ab98306a109c4988bb1cde687a24f4f8201fBarry Hayes        /* Destroy the heap.  Any outstanding pointers will point to
125b874ab98306a109c4988bb1cde687a24f4f8201fBarry Hayes         * unmapped memory (unless/until someone else maps it).  This
126b874ab98306a109c4988bb1cde687a24f4f8201fBarry Hayes         * frees gDvm.gcHeap as a side-effect.
127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
128a199eb70871a8c142a723d76b1b08939286a3199Carl Shapiro        dvmHeapSourceShutdown(&gDvm.gcHeap);
129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
130f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
133ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro * Shutdown any threads internal to the heap.
134ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro */
135ec805eaed940e40212e85b58b163c7649feaca56Carl Shapirovoid dvmHeapThreadShutdown(void)
136ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro{
137ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro    dvmHeapSourceThreadShutdown();
138ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro}
139ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro
140ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro/*
141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * We've been asked to allocate something we can't, e.g. an array so
1426da743bfe7c60ad873df72a3b6412137c4ac71dcAndy McFadden * large that (length * elementWidth) is larger than 2^31.
143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
1446da743bfe7c60ad873df72a3b6412137c4ac71dcAndy McFadden * _The Java Programming Language_, 4th edition, says, "you can be sure
1456da743bfe7c60ad873df72a3b6412137c4ac71dcAndy McFadden * that all SoftReferences to softly reachable objects will be cleared
1466da743bfe7c60ad873df72a3b6412137c4ac71dcAndy McFadden * before an OutOfMemoryError is thrown."
1476da743bfe7c60ad873df72a3b6412137c4ac71dcAndy McFadden *
1486da743bfe7c60ad873df72a3b6412137c4ac71dcAndy McFadden * It's unclear whether that holds for all situations where an OOM can
1496da743bfe7c60ad873df72a3b6412137c4ac71dcAndy McFadden * be thrown, or just in the context of an allocation that fails due
1506da743bfe7c60ad873df72a3b6412137c4ac71dcAndy McFadden * to lack of heap space.  For simplicity we just throw the exception.
1516da743bfe7c60ad873df72a3b6412137c4ac71dcAndy McFadden *
1526da743bfe7c60ad873df72a3b6412137c4ac71dcAndy McFadden * (OOM due to actually running out of space is handled elsewhere.)
153f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid dvmThrowBadAllocException(const char* msg)
155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
1566da743bfe7c60ad873df72a3b6412137c4ac71dcAndy McFadden    dvmThrowException("Ljava/lang/OutOfMemoryError;", msg);
157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
160f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Grab the lock, but put ourselves into THREAD_VMWAIT if it looks like
161f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * we're going to have to wait on the mutex.
162f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
163f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbool dvmLockHeap()
164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
165980ffb0243a1840ad0a93cfa06dfc02ca6f2d01cCarl Shapiro    if (dvmTryLockMutex(&gDvm.gcHeapLock) != 0) {
166f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Thread *self;
167f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        ThreadStatus oldStatus;
168f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
169f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        self = dvmThreadSelf();
1705617ad30c611f373e16bf10c0feec114faef54efCarl Shapiro        oldStatus = dvmChangeStatus(self, THREAD_VMWAIT);
171980ffb0243a1840ad0a93cfa06dfc02ca6f2d01cCarl Shapiro        dvmLockMutex(&gDvm.gcHeapLock);
1725617ad30c611f373e16bf10c0feec114faef54efCarl Shapiro        dvmChangeStatus(self, oldStatus);
173f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
174f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return true;
176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid dvmUnlockHeap()
179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmUnlockMutex(&gDvm.gcHeapLock);
181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* Pop an object from the list of pending finalizations and
184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * reference clears/enqueues, and return the object.
185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * The caller must call dvmReleaseTrackedAlloc()
186f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * on the object when finished.
187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
188f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Typically only called by the heap worker thread.
189f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
190f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectObject *dvmGetNextHeapWorkerObject(HeapWorkerOperation *op)
191f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
192f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    Object *obj;
193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    GcHeap *gcHeap = gDvm.gcHeap;
194f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
195f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    assert(op != NULL);
196f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
197f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmLockMutex(&gDvm.heapWorkerListLock);
198f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
199f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    obj = dvmHeapGetNextObjectFromLargeTable(&gcHeap->referenceOperations);
200f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (obj != NULL) {
201646ba0996da817deddb509b2130a6ad432096691Carl Shapiro        *op = WORKER_ENQUEUE;
202f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    } else {
203f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        obj = dvmHeapGetNextObjectFromLargeTable(
204f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                &gcHeap->pendingFinalizationRefs);
205f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (obj != NULL) {
206f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            *op = WORKER_FINALIZE;
207f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
208f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
209f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
210f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (obj != NULL) {
211f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /* Don't let the GC collect the object until the
212f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * worker thread is done with it.
213f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
214f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dvmAddTrackedAlloc(obj, NULL);
215f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
216f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
217f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmUnlockMutex(&gDvm.heapWorkerListLock);
218f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
219f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return obj;
220f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
221f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
222f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* Do a full garbage collection, which may grow the
223f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * heap as a side-effect if the live set is large.
224f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
225f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic void gcForMalloc(bool collectSoftReferences)
226f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
227f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (gDvm.allocProf.enabled) {
228f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Thread* self = dvmThreadSelf();
229f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        gDvm.allocProf.gcCount++;
230f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (self != NULL) {
231f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            self->allocProf.gcCount++;
232f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
233f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
234f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* This may adjust the soft limit as a side-effect.
235f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
236f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    LOGD_HEAP("dvmMalloc initiating GC%s\n",
237f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            collectSoftReferences ? "(collect SoftReferences)" : "");
2381b9b4e4b89e1c682b6684ae5e2a637e4497a67e9Barry Hayes    dvmCollectGarbageInternal(collectSoftReferences, GC_FOR_MALLOC);
239f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
240f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
241f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* Try as hard as possible to allocate some memory.
242f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
2436343bd071555458d0cb071f2eaf15b59b36771bfCarl Shapirostatic void *tryMalloc(size_t size)
244f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
2456343bd071555458d0cb071f2eaf15b59b36771bfCarl Shapiro    void *ptr;
246f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
247f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* Don't try too hard if there's no way the allocation is
248f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * going to succeed.  We have to collect SoftReferences before
249f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * throwing an OOME, though.
250f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
251f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (size >= gDvm.heapSizeMax) {
252f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOGW_HEAP("dvmMalloc(%zu/0x%08zx): "
253f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                "someone's allocating a huge buffer\n", size, size);
2546343bd071555458d0cb071f2eaf15b59b36771bfCarl Shapiro        ptr = NULL;
255f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto collect_soft_refs;
256f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
257f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
258f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project//TODO: figure out better heuristics
259f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project//    There will be a lot of churn if someone allocates a bunch of
260f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project//    big objects in a row, and we hit the frag case each time.
261f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project//    A full GC for each.
262f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project//    Maybe we grow the heap in bigger leaps
263f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project//    Maybe we skip the GC if the size is large and we did one recently
264f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project//      (number of allocations ago) (watch for thread effects)
265f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project//    DeflateTest allocs a bunch of ~128k buffers w/in 0-5 allocs of each other
266f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project//      (or, at least, there are only 0-5 objects swept each time)
267f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2686343bd071555458d0cb071f2eaf15b59b36771bfCarl Shapiro    ptr = dvmHeapSourceAlloc(size);
2696343bd071555458d0cb071f2eaf15b59b36771bfCarl Shapiro    if (ptr != NULL) {
2706343bd071555458d0cb071f2eaf15b59b36771bfCarl Shapiro        return ptr;
271f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
272f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
273ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro    /*
274ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro     * The allocation failed.  If the GC is running, block until it
275ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro     * completes and retry.
276ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro     */
277ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro    if (gDvm.gcHeap->gcRunning) {
278ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro        /*
279ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro         * The GC is concurrently tracing the heap.  Release the heap
280ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro         * lock, wait for the GC to complete, and retrying allocating.
281ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro         */
282ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro        dvmWaitForConcurrentGcToComplete();
283ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro        ptr = dvmHeapSourceAlloc(size);
284ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro        if (ptr != NULL) {
285ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro            return ptr;
286ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro        }
287ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro    }
288ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro    /*
289ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro     * Another failure.  Our thread was starved or there may be too
290ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro     * many live objects.  Try a foreground GC.  This will have no
291ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro     * effect if the concurrent GC is already running.
292f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
293f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gcForMalloc(false);
2946343bd071555458d0cb071f2eaf15b59b36771bfCarl Shapiro    ptr = dvmHeapSourceAlloc(size);
2956343bd071555458d0cb071f2eaf15b59b36771bfCarl Shapiro    if (ptr != NULL) {
2966343bd071555458d0cb071f2eaf15b59b36771bfCarl Shapiro        return ptr;
297f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
298f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
299f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* Even that didn't work;  this is an exceptional state.
300f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Try harder, growing the heap if necessary.
301f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
3026343bd071555458d0cb071f2eaf15b59b36771bfCarl Shapiro    ptr = dvmHeapSourceAllocAndGrow(size);
3036343bd071555458d0cb071f2eaf15b59b36771bfCarl Shapiro    if (ptr != NULL) {
304f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        size_t newHeapSize;
305f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
306f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        newHeapSize = dvmHeapSourceGetIdealFootprint();
307f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project//TODO: may want to grow a little bit more so that the amount of free
308f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project//      space is equal to the old free space + the utilization slop for
309f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project//      the new allocation.
310f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOGI_HEAP("Grow heap (frag case) to "
311f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                "%zu.%03zuMB for %zu-byte allocation\n",
312f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                FRACTIONAL_MB(newHeapSize), size);
3136343bd071555458d0cb071f2eaf15b59b36771bfCarl Shapiro        return ptr;
314f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
315f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
316f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* Most allocations should have succeeded by now, so the heap
317f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * is really full, really fragmented, or the requested size is
318f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * really big.  Do another GC, collecting SoftReferences this
319f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * time.  The VM spec requires that all SoftReferences have
320f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * been collected and cleared before throwing an OOME.
321f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
322f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project//TODO: wait for the finalizers from the previous GC to finish
323f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectcollect_soft_refs:
324f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    LOGI_HEAP("Forcing collection of SoftReferences for %zu-byte allocation\n",
325f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            size);
326f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gcForMalloc(true);
3276343bd071555458d0cb071f2eaf15b59b36771bfCarl Shapiro    ptr = dvmHeapSourceAllocAndGrow(size);
3286343bd071555458d0cb071f2eaf15b59b36771bfCarl Shapiro    if (ptr != NULL) {
3296343bd071555458d0cb071f2eaf15b59b36771bfCarl Shapiro        return ptr;
330f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
331f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project//TODO: maybe wait for finalizers and try one last time
332f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
333f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    LOGE_HEAP("Out of memory on a %zd-byte allocation.\n", size);
334f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project//TODO: tell the HeapSource to dump its state
335f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmDumpThread(dvmThreadSelf(), false);
336f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
337f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return NULL;
338f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
339f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
340f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* Throw an OutOfMemoryError if there's a thread to attach it to.
341f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Avoid recursing.
342f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
343f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * The caller must not be holding the heap lock, or else the allocations
344f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * in dvmThrowException() will deadlock.
345f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
346f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic void throwOOME()
347f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
348f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    Thread *self;
349f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
350f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if ((self = dvmThreadSelf()) != NULL) {
351f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /* If the current (failing) dvmMalloc() happened as part of thread
352f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * creation/attachment before the thread became part of the root set,
353f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * we can't rely on the thread-local trackedAlloc table, so
354f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * we can't keep track of a real allocated OOME object.  But, since
355f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * the thread is in the process of being created, it won't have
356f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * a useful stack anyway, so we may as well make things easier
357f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * by throwing the (stackless) pre-built OOME.
358f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
359f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (dvmIsOnThreadList(self) && !self->throwingOOME) {
360f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /* Let ourselves know that we tried to throw an OOM
361f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * error in the normal way in case we run out of
362f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * memory trying to allocate it inside dvmThrowException().
363f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
364f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            self->throwingOOME = true;
365f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
366f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /* Don't include a description string;
367f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * one fewer allocation.
368f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
369f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            dvmThrowException("Ljava/lang/OutOfMemoryError;", NULL);
370f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
371f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /*
372f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * This thread has already tried to throw an OutOfMemoryError,
373f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * which probably means that we're running out of memory
374f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * while recursively trying to throw.
375f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             *
376f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * To avoid any more allocation attempts, "throw" a pre-built
377f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * OutOfMemoryError object (which won't have a useful stack trace).
378f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             *
379f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * Note that since this call can't possibly allocate anything,
380f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * we don't care about the state of self->throwingOOME
381f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * (which will usually already be set).
382f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
383f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            dvmSetException(self, gDvm.outOfMemoryObj);
384f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
385f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /* We're done with the possible recursion.
386f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
387f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        self->throwingOOME = false;
388f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
389f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
390f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
391f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
392f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Allocate storage on the GC heap.  We guarantee 8-byte alignment.
393f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
394f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * The new storage is zeroed out.
395f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
396f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Note that, in rare cases, this could get called while a GC is in
397f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * progress.  If a non-VM thread tries to attach itself through JNI,
398f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * it will need to allocate some objects.  If this becomes annoying to
399f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * deal with, we can block it at the source, but holding the allocation
400f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * mutex should be enough.
401f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
402f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * In rare circumstances (JNI AttachCurrentThread) we can be called
403f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * from a non-VM thread.
404f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
405f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Use ALLOC_DONT_TRACK when we either don't want to track an allocation
406f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * (because it's being done for the interpreter "new" operation and will
407f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * be part of the root set immediately) or we can't (because this allocation
408f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * is for a brand new thread).
409f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
410f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Returns NULL and throws an exception on failure.
411f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
412f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * TODO: don't do a GC if the debugger thinks all threads are suspended
413f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
414f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid* dvmMalloc(size_t size, int flags)
415f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
416f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    GcHeap *gcHeap = gDvm.gcHeap;
417f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    void *ptr;
418f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
419f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#if defined(WITH_ALLOC_LIMITS)
420f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
421f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * See if they've exceeded the allocation limit for this thread.
422f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
423f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * A limit value of -1 means "no limit".
424f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
425f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * This is enabled at compile time because it requires us to do a
426f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * TLS lookup for the Thread pointer.  This has enough of a performance
427f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * impact that we don't want to do it if we don't have to.  (Now that
428f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * we're using gDvm.checkAllocLimits we may want to reconsider this,
429f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * but it's probably still best to just compile the check out of
430f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * production code -- one less thing to hit on every allocation.)
431f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
432f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (gDvm.checkAllocLimits) {
433f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Thread* self = dvmThreadSelf();
434f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (self != NULL) {
435f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int count = self->allocLimit;
436f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (count > 0) {
437f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                self->allocLimit--;
438f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else if (count == 0) {
439f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                /* fail! */
440f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                assert(!gDvm.initializing);
441f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                self->allocLimit = -1;
442f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                dvmThrowException("Ldalvik/system/AllocationLimitError;",
443f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    "thread allocation limit exceeded");
444f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                return NULL;
445f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
446f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
447f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
448f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
449f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (gDvm.allocationLimit >= 0) {
450f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        assert(!gDvm.initializing);
451f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        gDvm.allocationLimit = -1;
452f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dvmThrowException("Ldalvik/system/AllocationLimitError;",
453f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            "global allocation limit exceeded");
454f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return NULL;
455f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
456f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#endif
457f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
458f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmLockHeap();
459f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
460f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* Try as hard as possible to allocate some memory.
461f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
4626343bd071555458d0cb071f2eaf15b59b36771bfCarl Shapiro    ptr = tryMalloc(size);
4636343bd071555458d0cb071f2eaf15b59b36771bfCarl Shapiro    if (ptr != NULL) {
464f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /* We've got the memory.
465f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
466f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if ((flags & ALLOC_FINALIZABLE) != 0) {
467f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /* This object is an instance of a class that
468f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * overrides finalize().  Add it to the finalizable list.
469f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
470f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (!dvmHeapAddRefToLargeTable(&gcHeap->finalizableRefs,
4716343bd071555458d0cb071f2eaf15b59b36771bfCarl Shapiro                                    (Object *)ptr))
472f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            {
473f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                LOGE_HEAP("dvmMalloc(): no room for any more "
474f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        "finalizable objects\n");
475f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                dvmAbort();
476f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
477f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
478f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
479f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (gDvm.allocProf.enabled) {
480f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Thread* self = dvmThreadSelf();
481f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            gDvm.allocProf.allocCount++;
482f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            gDvm.allocProf.allocSize += size;
483f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (self != NULL) {
484f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                self->allocProf.allocCount++;
485f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                self->allocProf.allocSize += size;
486f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
487f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
488f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    } else {
489f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /* The allocation failed.
490f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
491f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
492f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (gDvm.allocProf.enabled) {
493f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Thread* self = dvmThreadSelf();
494f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            gDvm.allocProf.failedAllocCount++;
495f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            gDvm.allocProf.failedAllocSize += size;
496f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (self != NULL) {
497f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                self->allocProf.failedAllocCount++;
498f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                self->allocProf.failedAllocSize += size;
499f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
500f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
501f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
502f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
503f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmUnlockHeap();
504f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
505f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (ptr != NULL) {
506f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
507d4f78d3a764e6aa8f7174c78f537c016dac7f7ecBarry Hayes         * If caller hasn't asked us not to track it, add it to the
508d4f78d3a764e6aa8f7174c78f537c016dac7f7ecBarry Hayes         * internal tracking list.
509f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
510d4f78d3a764e6aa8f7174c78f537c016dac7f7ecBarry Hayes        if ((flags & ALLOC_DONT_TRACK) == 0) {
511f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            dvmAddTrackedAlloc(ptr, NULL);
512f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
513f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    } else {
514c3b92b26df6416d3179e865adccb283ee4170ab1Ben Cheng        /*
515f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * The allocation failed; throw an OutOfMemoryError.
516f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
517f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        throwOOME();
518f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
519f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
520f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return ptr;
521f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
522f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
523f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
524f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Returns true iff <obj> points to a valid allocated object.
525f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
526f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbool dvmIsValidObject(const Object* obj)
527f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
528f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* Don't bother if it's NULL or not 8-byte aligned.
529f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
5306343bd071555458d0cb071f2eaf15b59b36771bfCarl Shapiro    if (obj != NULL && ((uintptr_t)obj & (8-1)) == 0) {
531f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /* Even if the heap isn't locked, this shouldn't return
532f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * any false negatives.  The only mutation that could
533f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * be happening is allocation, which means that another
534f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * thread could be in the middle of a read-modify-write
535f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * to add a new bit for a new object.  However, that
536f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * RMW will have completed by the time any other thread
537f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * could possibly see the new pointer, so there is no
538f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * danger of dvmIsValidObject() being called on a valid
539f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * pointer whose bit isn't set.
540f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         *
541f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Freeing will only happen during the sweep phase, which
542f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * only happens while the heap is locked.
543f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
5446343bd071555458d0cb071f2eaf15b59b36771bfCarl Shapiro        return dvmHeapSourceContains(obj);
545f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
546f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return false;
547f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
548f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
549f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectsize_t dvmObjectSizeInHeap(const Object *obj)
550f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
5516343bd071555458d0cb071f2eaf15b59b36771bfCarl Shapiro    return dvmHeapSourceChunkSize(obj);
552f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
553f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
5546c5dd93d6b41d85f54c45816120081654ed2cbd8Carl Shapirostatic void verifyRootsAndHeap(void)
555962adba4e5db286a36bc8024f5c023bcf6f29312Barry Hayes{
556106c5fd9745a47d663e28217f3dd5ac48f606f81Carl Shapiro    dvmVerifyRoots();
557106c5fd9745a47d663e28217f3dd5ac48f606f81Carl Shapiro    dvmVerifyBitmap(dvmHeapSourceGetLiveBits());
558962adba4e5db286a36bc8024f5c023bcf6f29312Barry Hayes}
559962adba4e5db286a36bc8024f5c023bcf6f29312Barry Hayes
560962adba4e5db286a36bc8024f5c023bcf6f29312Barry Hayes/*
561f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Initiate garbage collection.
562f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
563f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * NOTES:
564f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * - If we don't hold gDvm.threadListLock, it's possible for a thread to
565f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *   be added to the thread list while we work.  The thread should NOT
566f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *   start executing, so this is only interesting when we start chasing
567f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *   thread stacks.  (Before we do so, grab the lock.)
568f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
569f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * We are not allowed to GC when the debugger has suspended the VM, which
570f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * is awkward because debugger requests can cause allocations.  The easiest
571f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * way to enforce this is to refuse to GC on an allocation made by the
572f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * JDWP thread -- we have to expand the heap or fail.
573f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
5742954074adc6a9793f38c0c58d03ec1dc057406ebCarl Shapirovoid dvmCollectGarbageInternal(bool clearSoftRefs, GcReason reason)
575f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
576f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    GcHeap *gcHeap = gDvm.gcHeap;
5778881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro    u4 rootSuspend, rootSuspendTime, rootStart, rootEnd;
5788881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro    u4 dirtySuspend, dirtyStart, dirtyEnd;
5798881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro    u4 totalTime;
580570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro    size_t numObjectsFreed, numBytesFreed;
581570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro    size_t currAllocated, currFootprint;
582570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro    size_t extAllocated, extLimit;
583570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro    size_t percentFree;
584d25566d9278e6424e521f4b7148ac31480e60c5cCarl Shapiro    GcMode gcMode;
585ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro    int oldThreadPriority = kInvalidPriority;
586f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
587f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* The heap lock must be held.
588f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
589f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
590f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (gcHeap->gcRunning) {
591f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOGW_HEAP("Attempted recursive GC\n");
592f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return;
593f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
59403f3b1394cc8421d125fd00455858944f0e9808dCarl Shapiro
595d25566d9278e6424e521f4b7148ac31480e60c5cCarl Shapiro    gcMode = (reason == GC_FOR_MALLOC) ? GC_PARTIAL : GC_FULL;
596f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gcHeap->gcRunning = true;
597f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
5988881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro    rootSuspend = dvmGetRelativeTimeMsec();
599f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmSuspendAllThreads(SUSPEND_FOR_GC);
60003f3b1394cc8421d125fd00455858944f0e9808dCarl Shapiro    rootStart = dvmGetRelativeTimeMsec();
6018881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro    rootSuspendTime = rootStart - rootSuspend;
602f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
603ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro    /*
604ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro     * If we are not marking concurrently raise the priority of the
605ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro     * thread performing the garbage collection.
606f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
607ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro    if (reason != GC_CONCURRENT) {
608ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro        /* Get the priority (the "nice" value) of the current thread.  The
609ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro         * getpriority() call can legitimately return -1, so we have to
610ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro         * explicitly test errno.
611f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
612ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro        errno = 0;
613ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro        int priorityResult = getpriority(PRIO_PROCESS, 0);
614ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro        if (errno != 0) {
615ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro            LOGI_HEAP("getpriority(self) failed: %s\n", strerror(errno));
616ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro        } else if (priorityResult > ANDROID_PRIORITY_NORMAL) {
617ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro            /* Current value is numerically greater than "normal", which
618ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro             * in backward UNIX terms means lower priority.
619ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro             */
620256fc159a267859c18e11e1d15fd7d97a59757c6San Mehat
621ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro            if (priorityResult >= ANDROID_PRIORITY_BACKGROUND) {
622ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro                set_sched_policy(dvmGetSysThreadId(), SP_FOREGROUND);
623ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro            }
624256fc159a267859c18e11e1d15fd7d97a59757c6San Mehat
625ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro            if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL) != 0) {
626ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro                LOGI_HEAP("Unable to elevate priority from %d to %d\n",
627ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro                          priorityResult, ANDROID_PRIORITY_NORMAL);
628ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro            } else {
629ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro                /* priority elevated; save value so we can restore it later */
630ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro                LOGD_HEAP("Elevating priority from %d to %d\n",
631ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro                          priorityResult, ANDROID_PRIORITY_NORMAL);
632ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro                oldThreadPriority = priorityResult;
633ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro            }
634f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
635f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
636f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
637f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* Wait for the HeapWorker thread to block.
638f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * (It may also already be suspended in interp code,
639f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * in which case it's not holding heapWorkerLock.)
640f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
641f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmLockMutex(&gDvm.heapWorkerLock);
642f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
643f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* Make sure that the HeapWorker thread hasn't become
644f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * wedged inside interp code.  If it has, this call will
645f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * print a message and abort the VM.
646f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
647f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmAssertHeapWorkerThreadRunning();
648f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
649f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* Lock the pendingFinalizationRefs list.
650f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
651f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Acquire the lock after suspending so the finalizer
652f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * thread can't block in the RUNNING state while
653f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * we try to suspend.
654f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
655f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmLockMutex(&gDvm.heapWorkerListLock);
656f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
657962adba4e5db286a36bc8024f5c023bcf6f29312Barry Hayes    if (gDvm.preVerify) {
6586c5dd93d6b41d85f54c45816120081654ed2cbd8Carl Shapiro        LOGV_HEAP("Verifying roots and heap before GC");
6596c5dd93d6b41d85f54c45816120081654ed2cbd8Carl Shapiro        verifyRootsAndHeap();
660962adba4e5db286a36bc8024f5c023bcf6f29312Barry Hayes    }
661962adba4e5db286a36bc8024f5c023bcf6f29312Barry Hayes
662f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmMethodTraceGCBegin();
663f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
664f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#if WITH_HPROF
665f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
666f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* Set DUMP_HEAP_ON_DDMS_UPDATE to 1 to enable heap dumps
667f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * whenever DDMS requests a heap update (HPIF chunk).
668f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * The output files will appear in /data/misc, which must
669f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * already exist.
670f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * You must define "WITH_HPROF := true" in your buildspec.mk
671f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * and recompile libdvm for this to work.
672f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
673f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * To enable stack traces for each allocation, define
674f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * "WITH_HPROF_STACK := true" in buildspec.mk.  This option slows down
675f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * allocations and also requires 8 additional bytes per object on the
676f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * GC heap.
677f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
678f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#define DUMP_HEAP_ON_DDMS_UPDATE 0
679f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#if DUMP_HEAP_ON_DDMS_UPDATE
680f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gcHeap->hprofDumpOnGc |= (gcHeap->ddmHpifWhen != 0);
681f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#endif
682f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
683f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (gcHeap->hprofDumpOnGc) {
684f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        char nameBuf[128];
685f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
68699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        gcHeap->hprofResult = -1;
68799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
688f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (gcHeap->hprofFileName == NULL) {
689f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /* no filename was provided; invent one */
690f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            sprintf(nameBuf, "/data/misc/heap-dump-tm%d-pid%d.hprof",
691f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                (int) time(NULL), (int) getpid());
692f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            gcHeap->hprofFileName = nameBuf;
693f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
6946bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden        gcHeap->hprofContext = hprofStartup(gcHeap->hprofFileName,
6954b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden                gcHeap->hprofFd, gcHeap->hprofDirectToDdms);
696f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (gcHeap->hprofContext != NULL) {
697f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            hprofStartHeapDump(gcHeap->hprofContext);
698f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
699f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        gcHeap->hprofDumpOnGc = false;
700f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        gcHeap->hprofFileName = NULL;
701f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
702f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#endif
703f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
704f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* Set up the marking context.
705f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
706d25566d9278e6424e521f4b7148ac31480e60c5cCarl Shapiro    if (!dvmHeapBeginMarkStep(gcMode)) {
70799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        LOGE_HEAP("dvmHeapBeginMarkStep failed; aborting\n");
70899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        dvmAbort();
70999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    }
710f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
711f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* Mark the set of objects that are strongly reachable from the roots.
712f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
713f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    LOGD_HEAP("Marking...");
714f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmHeapMarkRootSet();
715f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
716f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* dvmHeapScanMarkedObjects() will build the lists of known
717f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * instances of the Reference classes.
718f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
719f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gcHeap->softReferences = NULL;
720f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gcHeap->weakReferences = NULL;
721f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gcHeap->phantomReferences = NULL;
722f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
723ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro    if (reason == GC_CONCURRENT) {
724ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro        /*
725ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro         * Resume threads while tracing from the roots.  We unlock the
726ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro         * heap to allow mutator threads to allocate from free space.
727ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro         */
72803f3b1394cc8421d125fd00455858944f0e9808dCarl Shapiro        rootEnd = dvmGetRelativeTimeMsec();
729106c5fd9745a47d663e28217f3dd5ac48f606f81Carl Shapiro        dvmClearCardTable();
730ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro        dvmUnlockHeap();
731ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro        dvmResumeAllThreads(SUSPEND_FOR_GC);
732ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro    }
733ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro
734f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* Recursively mark any objects that marked objects point to strongly.
735f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * If we're not collecting soft references, soft-reachable
736f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * objects will also be marked.
737f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
738f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    LOGD_HEAP("Recursing...");
739f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmHeapScanMarkedObjects();
740f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
741ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro    if (reason == GC_CONCURRENT) {
742ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro        /*
743ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro         * Re-acquire the heap lock and perform the final thread
744ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro         * suspension.
745ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro         */
746ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro        dvmLockHeap();
7478881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro        dirtySuspend = dvmGetRelativeTimeMsec();
748ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro        dvmSuspendAllThreads(SUSPEND_FOR_GC);
74903f3b1394cc8421d125fd00455858944f0e9808dCarl Shapiro        dirtyStart = dvmGetRelativeTimeMsec();
750ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro        /*
751ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro         * As no barrier intercepts root updates, we conservatively
752ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro         * assume all roots may be gray and re-mark them.
753ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro         */
754106c5fd9745a47d663e28217f3dd5ac48f606f81Carl Shapiro        dvmHeapReMarkRootSet();
755ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro        /*
7565ba39376c5b7a5878f234a689a51c74783583b4bCarl Shapiro         * With the exception of reference objects and weak interned
7575ba39376c5b7a5878f234a689a51c74783583b4bCarl Shapiro         * strings, all gray objects should now be on dirty cards.
7585ba39376c5b7a5878f234a689a51c74783583b4bCarl Shapiro         */
7595ba39376c5b7a5878f234a689a51c74783583b4bCarl Shapiro        if (gDvm.verifyCardTable) {
7605ba39376c5b7a5878f234a689a51c74783583b4bCarl Shapiro            dvmVerifyCardTable();
7615ba39376c5b7a5878f234a689a51c74783583b4bCarl Shapiro        }
7625ba39376c5b7a5878f234a689a51c74783583b4bCarl Shapiro        /*
763ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro         * Recursively mark gray objects pointed to by the roots or by
764ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro         * heap objects dirtied during the concurrent mark.
765ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro         */
766106c5fd9745a47d663e28217f3dd5ac48f606f81Carl Shapiro        dvmHeapReScanMarkedObjects();
767ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro    }
768ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro
769f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* All strongly-reachable objects have now been marked.
770f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
7712954074adc6a9793f38c0c58d03ec1dc057406ebCarl Shapiro    LOGD_HEAP("Handling soft references...");
7722954074adc6a9793f38c0c58d03ec1dc057406ebCarl Shapiro    if (!clearSoftRefs) {
7732954074adc6a9793f38c0c58d03ec1dc057406ebCarl Shapiro        dvmHandleSoftRefs(&gcHeap->softReferences);
7742954074adc6a9793f38c0c58d03ec1dc057406ebCarl Shapiro    }
7752954074adc6a9793f38c0c58d03ec1dc057406ebCarl Shapiro    dvmClearWhiteRefs(&gcHeap->softReferences);
7762954074adc6a9793f38c0c58d03ec1dc057406ebCarl Shapiro
777f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    LOGD_HEAP("Handling weak references...");
7782954074adc6a9793f38c0c58d03ec1dc057406ebCarl Shapiro    dvmClearWhiteRefs(&gcHeap->weakReferences);
779f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
780f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* Once all weak-reachable objects have been taken
781f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * care of, any remaining unmarked objects can be finalized.
782f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
783f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    LOGD_HEAP("Finding finalizations...");
784f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmHeapScheduleFinalizations();
785f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
7862954074adc6a9793f38c0c58d03ec1dc057406ebCarl Shapiro    LOGD_HEAP("Handling f-reachable soft references...");
7872954074adc6a9793f38c0c58d03ec1dc057406ebCarl Shapiro    dvmClearWhiteRefs(&gcHeap->softReferences);
7882954074adc6a9793f38c0c58d03ec1dc057406ebCarl Shapiro
7892954074adc6a9793f38c0c58d03ec1dc057406ebCarl Shapiro    LOGD_HEAP("Handling f-reachable weak references...");
7902954074adc6a9793f38c0c58d03ec1dc057406ebCarl Shapiro    dvmClearWhiteRefs(&gcHeap->weakReferences);
7912954074adc6a9793f38c0c58d03ec1dc057406ebCarl Shapiro
792f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* Any remaining objects that are not pending finalization
793f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * could be phantom-reachable.  This will mark any phantom-reachable
794f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * objects, as well as enqueue their references.
795f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
796f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    LOGD_HEAP("Handling phantom references...");
7972954074adc6a9793f38c0c58d03ec1dc057406ebCarl Shapiro    dvmClearWhiteRefs(&gcHeap->phantomReferences);
798f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
7998881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro#if defined(WITH_JIT)
8008881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro    /*
8018881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro     * Patching a chaining cell is very cheap as it only updates 4 words. It's
8028881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro     * the overhead of stopping all threads and synchronizing the I/D cache
8038881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro     * that makes it expensive.
8048881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro     *
8058881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro     * Therefore we batch those work orders in a queue and go through them
8068881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro     * when threads are suspended for GC.
8078881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro     */
8088881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro    dvmCompilerPerformSafePointChecks();
809f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#endif
8108881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro
811f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    LOGD_HEAP("Sweeping...");
812f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
8138881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro    dvmHeapSweepSystemWeaks();
8148881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro
8158881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro    /*
8168881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro     * Live objects have a bit set in the mark bitmap, swap the mark
8178881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro     * and live bitmaps.  The sweep can proceed concurrently viewing
8188881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro     * the new live bitmap as the old mark bitmap, and vice versa.
8198881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro     */
8208881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro    dvmHeapSourceSwapBitmaps();
8218881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro
8228881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro    if (gDvm.postVerify) {
8238881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro        LOGV_HEAP("Verifying roots and heap after GC");
8248881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro        verifyRootsAndHeap();
8258881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro    }
8268881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro
8278881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro    if (reason == GC_CONCURRENT) {
8288881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro        dirtyEnd = dvmGetRelativeTimeMsec();
8298881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro        dvmUnlockHeap();
8308881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro        dvmResumeAllThreads(SUSPEND_FOR_GC);
8318881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro    }
8328881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro    dvmHeapSweepUnmarkedObjects(gcMode, reason == GC_CONCURRENT,
833570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro                                &numObjectsFreed, &numBytesFreed);
834f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    LOGD_HEAP("Cleaning up...");
835f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmHeapFinishMarkStep();
8368881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro    if (reason == GC_CONCURRENT) {
8378881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro        dvmLockHeap();
8388881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro    }
839f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
840f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    LOGD_HEAP("Done.");
841f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
842f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* Now's a good time to adjust the heap size, since
843f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * we know what our utilization is.
844f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
845f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * This doesn't actually resize any memory;
846f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * it just lets the heap grow more when necessary.
847f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
848b755f9a3caeaf65e95480ac66c2c95553bf79389Carl Shapiro    if (reason != GC_EXTERNAL_ALLOC) {
849b755f9a3caeaf65e95480ac66c2c95553bf79389Carl Shapiro        dvmHeapSourceGrowForUtilization();
850b755f9a3caeaf65e95480ac66c2c95553bf79389Carl Shapiro    }
851f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
852570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro    currAllocated = dvmHeapSourceGetValue(HS_BYTES_ALLOCATED, NULL, 0);
853570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro    currFootprint = dvmHeapSourceGetValue(HS_FOOTPRINT, NULL, 0);
854570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro
855f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#if WITH_HPROF
856f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (gcHeap->hprofContext != NULL) {
857f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        hprofFinishHeapDump(gcHeap->hprofContext);
858f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project//TODO: write a HEAP_SUMMARY record
85999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        if (hprofShutdown(gcHeap->hprofContext))
86099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            gcHeap->hprofResult = 0;    /* indicate success */
861f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        gcHeap->hprofContext = NULL;
862f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
863f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#endif
864f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
865f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* Now that we've freed up the GC heap, return any large
866f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * free chunks back to the system.  They'll get paged back
867f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * in the next time they're used.  Don't do it immediately,
868f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * though;  if the process is still allocating a bunch of
869f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * memory, we'll be taking a ton of page faults that we don't
870f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * necessarily need to.
871f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
872f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Cancel any old scheduled trims, and schedule a new one.
873f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
874f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmScheduleHeapSourceTrim(5);  // in seconds
875f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
876f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmMethodTraceGCEnd();
877962adba4e5db286a36bc8024f5c023bcf6f29312Barry Hayes    LOGV_HEAP("GC finished");
878962adba4e5db286a36bc8024f5c023bcf6f29312Barry Hayes
879f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gcHeap->gcRunning = false;
880f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
881962adba4e5db286a36bc8024f5c023bcf6f29312Barry Hayes    LOGV_HEAP("Resuming threads");
882f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmUnlockMutex(&gDvm.heapWorkerListLock);
883f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmUnlockMutex(&gDvm.heapWorkerLock);
884f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
885ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro    if (reason == GC_CONCURRENT) {
886ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro        /*
887ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro         * Wake-up any threads that blocked after a failed allocation
888ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro         * request.
889ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro         */
890ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro        dvmBroadcastCond(&gDvm.gcHeapCond);
891ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro    }
892ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro
893ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro    if (reason != GC_CONCURRENT) {
8948881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro        dirtyEnd = dvmGetRelativeTimeMsec();
8958881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro        dvmResumeAllThreads(SUSPEND_FOR_GC);
896ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro        if (oldThreadPriority != kInvalidPriority) {
897ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro            if (setpriority(PRIO_PROCESS, 0, oldThreadPriority) != 0) {
898ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro                LOGW_HEAP("Unable to reset priority to %d: %s\n",
899ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro                          oldThreadPriority, strerror(errno));
900ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro            } else {
901ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro                LOGD_HEAP("Reset priority to %d\n", oldThreadPriority);
902ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro            }
903256fc159a267859c18e11e1d15fd7d97a59757c6San Mehat
904ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro            if (oldThreadPriority >= ANDROID_PRIORITY_BACKGROUND) {
905ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro                set_sched_policy(dvmGetSysThreadId(), SP_BACKGROUND);
906ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro            }
907256fc159a267859c18e11e1d15fd7d97a59757c6San Mehat        }
908f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
909f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
910570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro    extAllocated = dvmHeapSourceGetValue(HS_EXTERNAL_BYTES_ALLOCATED, NULL, 0);
911570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro    extLimit = dvmHeapSourceGetValue(HS_EXTERNAL_LIMIT, NULL, 0);
912570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro    percentFree = 100 - (size_t)(100.0f * (float)currAllocated / currFootprint);
91303f3b1394cc8421d125fd00455858944f0e9808dCarl Shapiro    if (reason != GC_CONCURRENT) {
91403f3b1394cc8421d125fd00455858944f0e9808dCarl Shapiro        u4 markSweepTime = dirtyEnd - rootStart;
915570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro        bool isSmall = numBytesFreed > 0 && numBytesFreed < 1024;
9168881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro        totalTime = rootSuspendTime + markSweepTime;
91771978ec653badfdbedcc792fd7d33caafe491ee7Carl Shapiro        LOGD("%s freed %s%zdK, %d%% free %zdK/%zdK, external %zdK/%zdK, "
918570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro             "paused %ums",
919570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro             GcReasonStr[reason],
920570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro             isSmall ? "<" : "",
921570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro             numBytesFreed ? MAX(numBytesFreed / 1024, 1) : 0,
922570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro             percentFree,
923570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro             currAllocated / 1024, currFootprint / 1024,
924570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro             extAllocated / 1024, extLimit / 1024,
925570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro             markSweepTime);
92603f3b1394cc8421d125fd00455858944f0e9808dCarl Shapiro    } else {
9278881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro        u4 rootTime = rootEnd - rootStart;
9288881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro        u4 dirtySuspendTime = dirtyStart - dirtySuspend;
9298881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro        u4 dirtyTime = dirtyEnd - dirtyStart;
930570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro        bool isSmall = numBytesFreed > 0 && numBytesFreed < 1024;
93103f3b1394cc8421d125fd00455858944f0e9808dCarl Shapiro        totalTime = rootSuspendTime + rootTime + dirtySuspendTime + dirtyTime;
93271978ec653badfdbedcc792fd7d33caafe491ee7Carl Shapiro        LOGD("%s freed %s%zdK, %d%% free %zdK/%zdK, external %zdK/%zdK, "
933570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro             "paused %ums+%ums",
934570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro             GcReasonStr[reason],
935570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro             isSmall ? "<" : "",
936570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro             numBytesFreed ? MAX(numBytesFreed / 1024, 1) : 0,
937570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro             percentFree,
938570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro             currAllocated / 1024, currFootprint / 1024,
939570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro             extAllocated / 1024, extLimit / 1024,
940570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro             rootTime, dirtyTime);
941570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro    }
942570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro    dvmLogGcStats(numObjectsFreed, numBytesFreed, totalTime);
943f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (gcHeap->ddmHpifWhen != 0) {
944f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOGD_HEAP("Sending VM heap info to DDM\n");
945f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dvmDdmSendHeapInfo(gcHeap->ddmHpifWhen, false);
946f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
947f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (gcHeap->ddmHpsgWhen != 0) {
948f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOGD_HEAP("Dumping VM heap to DDM\n");
949f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dvmDdmSendHeapSegments(false, false);
950f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
951f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (gcHeap->ddmNhsgWhen != 0) {
952f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOGD_HEAP("Dumping native heap to DDM\n");
953f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dvmDdmSendHeapSegments(false, true);
954f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
955f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
956f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
957ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapirovoid dvmWaitForConcurrentGcToComplete(void)
958ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro{
959ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro    Thread *self = dvmThreadSelf();
960ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro    ThreadStatus oldStatus;
961ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro    assert(self != NULL);
962ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro    oldStatus = dvmChangeStatus(self, THREAD_VMWAIT);
963ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro    dvmWaitCond(&gDvm.gcHeapCond, &gDvm.gcHeapLock);
964ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro    dvmChangeStatus(self, oldStatus);
965ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro}
966ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro
967f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#if WITH_HPROF
968f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
969f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Perform garbage collection, writing heap information to the specified file.
970f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
9714b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden * If "fd" is >= 0, the output will be written to that file descriptor.
9724b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden * Otherwise, "fileName" is used to create an output file.
9734b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden *
974f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * If "fileName" is NULL, a suitable name will be generated automatically.
9754b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden * (TODO: remove this when the SIGUSR1 feature goes away)
9764b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden *
9774b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden * If "directToDdms" is set, the other arguments are ignored, and data is
9784b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden * sent directly to DDMS.
97999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project *
98099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * Returns 0 on success, or an error code on failure.
981f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
9824b851a75f7712086a9fc4427f68c99b83725f37dAndy McFaddenint hprofDumpHeap(const char* fileName, int fd, bool directToDdms)
983f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
98499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    int result;
98599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
986f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmLockMutex(&gDvm.gcHeapLock);
987f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
988f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gDvm.gcHeap->hprofDumpOnGc = true;
989f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gDvm.gcHeap->hprofFileName = fileName;
9904b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden    gDvm.gcHeap->hprofFd = fd;
9916bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden    gDvm.gcHeap->hprofDirectToDdms = directToDdms;
9921b9b4e4b89e1c682b6684ae5e2a637e4497a67e9Barry Hayes    dvmCollectGarbageInternal(false, GC_HPROF_DUMP_HEAP);
99399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    result = gDvm.gcHeap->hprofResult;
994f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
995f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmUnlockMutex(&gDvm.gcHeapLock);
99699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
99799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    return result;
998f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
999f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1000f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid dvmHeapSetHprofGcScanState(hprof_heap_tag_t state, u4 threadSerialNumber)
1001f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
1002f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (gDvm.gcHeap->hprofContext != NULL) {
1003f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        hprofSetGcScanState(gDvm.gcHeap->hprofContext, state,
1004f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                threadSerialNumber);
1005f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1006f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
1007f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#endif
1008