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/Heap.h"
23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include "alloc/HeapInternal.h"
24f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include "alloc/DdmHeap.h"
25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include "alloc/HeapSource.h"
26f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include "alloc/MarkSweep.h"
27e6c0ef210ee6c62cf4c63d50c04f451d5fa505f5Elliott Hughes#include "os/os.h"
285a2056ca8c7e7c0ed9f51d68cedbee59cc936685San Mehat
29f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include <sys/time.h>
30f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include <sys/resource.h>
31f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include <limits.h>
32f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include <errno.h>
33f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
34cc6f5118d19bae06cb80841386a0c95f24616a65Carl Shapirostatic const GcSpec kGcForMallocSpec = {
359b6881c26d58a46e6478294d83554fb9e3a85625Carl Shapiro    true,  /* isPartial */
369b6881c26d58a46e6478294d83554fb9e3a85625Carl Shapiro    false,  /* isConcurrent */
37ae188c676c681e47a93ade7fdf0144099b470e03Carl Shapiro    true,  /* doPreserve */
38cc6f5118d19bae06cb80841386a0c95f24616a65Carl Shapiro    "GC_FOR_ALLOC"
391b9b4e4b89e1c682b6684ae5e2a637e4497a67e9Barry Hayes};
401b9b4e4b89e1c682b6684ae5e2a637e4497a67e9Barry Hayes
41cc6f5118d19bae06cb80841386a0c95f24616a65Carl Shapiroconst GcSpec *GC_FOR_MALLOC = &kGcForMallocSpec;
42cc6f5118d19bae06cb80841386a0c95f24616a65Carl Shapiro
43cc6f5118d19bae06cb80841386a0c95f24616a65Carl Shapirostatic const GcSpec kGcConcurrentSpec  = {
449b6881c26d58a46e6478294d83554fb9e3a85625Carl Shapiro    true,  /* isPartial */
459b6881c26d58a46e6478294d83554fb9e3a85625Carl Shapiro    true,  /* isConcurrent */
46ae188c676c681e47a93ade7fdf0144099b470e03Carl Shapiro    true,  /* doPreserve */
47cc6f5118d19bae06cb80841386a0c95f24616a65Carl Shapiro    "GC_CONCURRENT"
48cc6f5118d19bae06cb80841386a0c95f24616a65Carl Shapiro};
49cc6f5118d19bae06cb80841386a0c95f24616a65Carl Shapiro
50cc6f5118d19bae06cb80841386a0c95f24616a65Carl Shapiroconst GcSpec *GC_CONCURRENT = &kGcConcurrentSpec;
51cc6f5118d19bae06cb80841386a0c95f24616a65Carl Shapiro
52cc6f5118d19bae06cb80841386a0c95f24616a65Carl Shapirostatic const GcSpec kGcExplicitSpec = {
539b6881c26d58a46e6478294d83554fb9e3a85625Carl Shapiro    false,  /* isPartial */
549b6881c26d58a46e6478294d83554fb9e3a85625Carl Shapiro    true,  /* isConcurrent */
55ae188c676c681e47a93ade7fdf0144099b470e03Carl Shapiro    true,  /* doPreserve */
56cc6f5118d19bae06cb80841386a0c95f24616a65Carl Shapiro    "GC_EXPLICIT"
57cc6f5118d19bae06cb80841386a0c95f24616a65Carl Shapiro};
58cc6f5118d19bae06cb80841386a0c95f24616a65Carl Shapiro
59cc6f5118d19bae06cb80841386a0c95f24616a65Carl Shapiroconst GcSpec *GC_EXPLICIT = &kGcExplicitSpec;
60cc6f5118d19bae06cb80841386a0c95f24616a65Carl Shapiro
61cc6f5118d19bae06cb80841386a0c95f24616a65Carl Shapirostatic const GcSpec kGcBeforeOomSpec = {
629b6881c26d58a46e6478294d83554fb9e3a85625Carl Shapiro    false,  /* isPartial */
639b6881c26d58a46e6478294d83554fb9e3a85625Carl Shapiro    false,  /* isConcurrent */
64ae188c676c681e47a93ade7fdf0144099b470e03Carl Shapiro    false,  /* doPreserve */
65cc6f5118d19bae06cb80841386a0c95f24616a65Carl Shapiro    "GC_BEFORE_OOM"
66cc6f5118d19bae06cb80841386a0c95f24616a65Carl Shapiro};
67cc6f5118d19bae06cb80841386a0c95f24616a65Carl Shapiro
68cc6f5118d19bae06cb80841386a0c95f24616a65Carl Shapiroconst GcSpec *GC_BEFORE_OOM = &kGcBeforeOomSpec;
69cc6f5118d19bae06cb80841386a0c95f24616a65Carl Shapiro
70f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
71f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Initialize the GC heap.
72f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
73f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Returns true if successful, false otherwise.
74f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
75f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbool dvmHeapStartup()
76f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
77f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    GcHeap *gcHeap;
78f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
79df9f08b877ecfd8ebadea822bb9e066ee7d30433Carl Shapiro    if (gDvm.heapGrowthLimit == 0) {
80df9f08b877ecfd8ebadea822bb9e066ee7d30433Carl Shapiro        gDvm.heapGrowthLimit = gDvm.heapMaximumSize;
81df9f08b877ecfd8ebadea822bb9e066ee7d30433Carl Shapiro    }
82df9f08b877ecfd8ebadea822bb9e066ee7d30433Carl Shapiro
83df9f08b877ecfd8ebadea822bb9e066ee7d30433Carl Shapiro    gcHeap = dvmHeapSourceStartup(gDvm.heapStartingSize,
84df9f08b877ecfd8ebadea822bb9e066ee7d30433Carl Shapiro                                  gDvm.heapMaximumSize,
85df9f08b877ecfd8ebadea822bb9e066ee7d30433Carl Shapiro                                  gDvm.heapGrowthLimit);
86f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (gcHeap == NULL) {
87f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return false;
88f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
89f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gcHeap->ddmHpifWhen = 0;
90f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gcHeap->ddmHpsgWhen = 0;
91f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gcHeap->ddmHpsgWhat = 0;
92f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gcHeap->ddmNhsgWhen = 0;
93f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gcHeap->ddmNhsgWhat = 0;
94f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gDvm.gcHeap = gcHeap;
95f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
96ce87bfed41bbe4248b2770fb1a90f34b2518f6faCarl Shapiro    /* Set up the lists we'll use for cleared reference objects.
97f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
98ce87bfed41bbe4248b2770fb1a90f34b2518f6faCarl Shapiro    gcHeap->clearedReferences = NULL;
99f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
100af6cf54652d1b27885b99e216bee29b955052630Andy McFadden    if (!dvmCardTableStartup(gDvm.heapMaximumSize, gDvm.heapGrowthLimit)) {
101b874ab98306a109c4988bb1cde687a24f4f8201fBarry Hayes        LOGE_HEAP("card table startup failed.");
102b874ab98306a109c4988bb1cde687a24f4f8201fBarry Hayes        return false;
103b874ab98306a109c4988bb1cde687a24f4f8201fBarry Hayes    }
104b874ab98306a109c4988bb1cde687a24f4f8201fBarry Hayes
105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return true;
106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1081e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapirobool dvmHeapStartupAfterZygote()
109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
110ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro    return dvmHeapSourceStartupAfterZygote();
111f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
112f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid dvmHeapShutdown()
114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project//TODO: make sure we're locked
116f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (gDvm.gcHeap != NULL) {
117b874ab98306a109c4988bb1cde687a24f4f8201fBarry Hayes        dvmCardTableShutdown();
118b874ab98306a109c4988bb1cde687a24f4f8201fBarry Hayes        /* Destroy the heap.  Any outstanding pointers will point to
119b874ab98306a109c4988bb1cde687a24f4f8201fBarry Hayes         * unmapped memory (unless/until someone else maps it).  This
120b874ab98306a109c4988bb1cde687a24f4f8201fBarry Hayes         * frees gDvm.gcHeap as a side-effect.
121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
122a199eb70871a8c142a723d76b1b08939286a3199Carl Shapiro        dvmHeapSourceShutdown(&gDvm.gcHeap);
123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
125f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
126f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
127ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro * Shutdown any threads internal to the heap.
128ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro */
1291e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapirovoid dvmHeapThreadShutdown()
130ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro{
131ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro    dvmHeapSourceThreadShutdown();
132ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro}
133ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro
134ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro/*
135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Grab the lock, but put ourselves into THREAD_VMWAIT if it looks like
136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * we're going to have to wait on the mutex.
137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbool dvmLockHeap()
139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
140980ffb0243a1840ad0a93cfa06dfc02ca6f2d01cCarl Shapiro    if (dvmTryLockMutex(&gDvm.gcHeapLock) != 0) {
141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Thread *self;
142f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        ThreadStatus oldStatus;
143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        self = dvmThreadSelf();
1455617ad30c611f373e16bf10c0feec114faef54efCarl Shapiro        oldStatus = dvmChangeStatus(self, THREAD_VMWAIT);
146980ffb0243a1840ad0a93cfa06dfc02ca6f2d01cCarl Shapiro        dvmLockMutex(&gDvm.gcHeapLock);
1475617ad30c611f373e16bf10c0feec114faef54efCarl Shapiro        dvmChangeStatus(self, oldStatus);
148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
150f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return true;
151f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
152f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
153f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid dvmUnlockHeap()
154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmUnlockMutex(&gDvm.gcHeapLock);
156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* Do a full garbage collection, which may grow the
159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * heap as a side-effect if the live set is large.
160f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
161a371fad368c4d697b2906079bfbe8059269ed362Carl Shapirostatic void gcForMalloc(bool clearSoftReferences)
162f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
163f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (gDvm.allocProf.enabled) {
164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Thread* self = dvmThreadSelf();
165f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        gDvm.allocProf.gcCount++;
166f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (self != NULL) {
167f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            self->allocProf.gcCount++;
168f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
169f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
170f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* This may adjust the soft limit as a side-effect.
171f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
172cc6f5118d19bae06cb80841386a0c95f24616a65Carl Shapiro    const GcSpec *spec = clearSoftReferences ? GC_BEFORE_OOM : GC_FOR_MALLOC;
173cc6f5118d19bae06cb80841386a0c95f24616a65Carl Shapiro    dvmCollectGarbageInternal(spec);
174f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* Try as hard as possible to allocate some memory.
177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
1786343bd071555458d0cb071f2eaf15b59b36771bfCarl Shapirostatic void *tryMalloc(size_t size)
179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
1806343bd071555458d0cb071f2eaf15b59b36771bfCarl Shapiro    void *ptr;
181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* Don't try too hard if there's no way the allocation is
183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * going to succeed.  We have to collect SoftReferences before
184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * throwing an OOME, though.
185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
186df9f08b877ecfd8ebadea822bb9e066ee7d30433Carl Shapiro    if (size >= gDvm.heapGrowthLimit) {
187e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block        ALOGW("%zd byte allocation exceeds the %zd byte maximum heap size",
1882384bdf512d0609c747af03256654fde03093844Carl Shapiro             size, gDvm.heapGrowthLimit);
1896343bd071555458d0cb071f2eaf15b59b36771bfCarl Shapiro        ptr = NULL;
190f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto collect_soft_refs;
191f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
192f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project//TODO: figure out better heuristics
194f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project//    There will be a lot of churn if someone allocates a bunch of
195f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project//    big objects in a row, and we hit the frag case each time.
196f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project//    A full GC for each.
197f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project//    Maybe we grow the heap in bigger leaps
198f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project//    Maybe we skip the GC if the size is large and we did one recently
199f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project//      (number of allocations ago) (watch for thread effects)
200f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project//    DeflateTest allocs a bunch of ~128k buffers w/in 0-5 allocs of each other
201f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project//      (or, at least, there are only 0-5 objects swept each time)
202f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2036343bd071555458d0cb071f2eaf15b59b36771bfCarl Shapiro    ptr = dvmHeapSourceAlloc(size);
2046343bd071555458d0cb071f2eaf15b59b36771bfCarl Shapiro    if (ptr != NULL) {
2056343bd071555458d0cb071f2eaf15b59b36771bfCarl Shapiro        return ptr;
206f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
207f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
208ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro    /*
209ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro     * The allocation failed.  If the GC is running, block until it
210ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro     * completes and retry.
211ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro     */
212ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro    if (gDvm.gcHeap->gcRunning) {
213ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro        /*
214ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro         * The GC is concurrently tracing the heap.  Release the heap
215ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro         * lock, wait for the GC to complete, and retrying allocating.
216ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro         */
217ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro        dvmWaitForConcurrentGcToComplete();
218ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro        ptr = dvmHeapSourceAlloc(size);
219ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro        if (ptr != NULL) {
220ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro            return ptr;
221ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro        }
222ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro    }
223ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro    /*
224ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro     * Another failure.  Our thread was starved or there may be too
225ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro     * many live objects.  Try a foreground GC.  This will have no
226ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro     * effect if the concurrent GC is already running.
227f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
228f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gcForMalloc(false);
2296343bd071555458d0cb071f2eaf15b59b36771bfCarl Shapiro    ptr = dvmHeapSourceAlloc(size);
2306343bd071555458d0cb071f2eaf15b59b36771bfCarl Shapiro    if (ptr != NULL) {
2316343bd071555458d0cb071f2eaf15b59b36771bfCarl Shapiro        return ptr;
232f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
233f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
234f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* Even that didn't work;  this is an exceptional state.
235f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Try harder, growing the heap if necessary.
236f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
2376343bd071555458d0cb071f2eaf15b59b36771bfCarl Shapiro    ptr = dvmHeapSourceAllocAndGrow(size);
2386343bd071555458d0cb071f2eaf15b59b36771bfCarl Shapiro    if (ptr != NULL) {
239f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        size_t newHeapSize;
240f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
241f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        newHeapSize = dvmHeapSourceGetIdealFootprint();
242f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project//TODO: may want to grow a little bit more so that the amount of free
243f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project//      space is equal to the old free space + the utilization slop for
244f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project//      the new allocation.
245f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOGI_HEAP("Grow heap (frag case) to "
2466f3c21fb026d9489e5046416bcd5a84fa8e4615bDan Bornstein                "%zu.%03zuMB for %zu-byte allocation",
247f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                FRACTIONAL_MB(newHeapSize), size);
2486343bd071555458d0cb071f2eaf15b59b36771bfCarl Shapiro        return ptr;
249f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
250f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
251f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* Most allocations should have succeeded by now, so the heap
252f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * is really full, really fragmented, or the requested size is
253f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * really big.  Do another GC, collecting SoftReferences this
254f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * time.  The VM spec requires that all SoftReferences have
255f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * been collected and cleared before throwing an OOME.
256f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
257f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project//TODO: wait for the finalizers from the previous GC to finish
258f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectcollect_soft_refs:
25960fc806b679a3655c228b4093058c59941a49cfeDan Bornstein    LOGI_HEAP("Forcing collection of SoftReferences for %zu-byte allocation",
260f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            size);
261f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gcForMalloc(true);
2626343bd071555458d0cb071f2eaf15b59b36771bfCarl Shapiro    ptr = dvmHeapSourceAllocAndGrow(size);
2636343bd071555458d0cb071f2eaf15b59b36771bfCarl Shapiro    if (ptr != NULL) {
2646343bd071555458d0cb071f2eaf15b59b36771bfCarl Shapiro        return ptr;
265f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
266f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project//TODO: maybe wait for finalizers and try one last time
267f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
26860fc806b679a3655c228b4093058c59941a49cfeDan Bornstein    LOGE_HEAP("Out of memory on a %zd-byte allocation.", size);
269f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project//TODO: tell the HeapSource to dump its state
270f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmDumpThread(dvmThreadSelf(), false);
271f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
272f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return NULL;
273f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
274f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
275f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* Throw an OutOfMemoryError if there's a thread to attach it to.
276f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Avoid recursing.
277f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
278f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * The caller must not be holding the heap lock, or else the allocations
279f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * in dvmThrowException() will deadlock.
280f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
281f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic void throwOOME()
282f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
283f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    Thread *self;
284f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
285f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if ((self = dvmThreadSelf()) != NULL) {
286f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /* If the current (failing) dvmMalloc() happened as part of thread
287f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * creation/attachment before the thread became part of the root set,
288f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * we can't rely on the thread-local trackedAlloc table, so
289f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * we can't keep track of a real allocated OOME object.  But, since
290f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * the thread is in the process of being created, it won't have
291f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * a useful stack anyway, so we may as well make things easier
292f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * by throwing the (stackless) pre-built OOME.
293f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
294f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (dvmIsOnThreadList(self) && !self->throwingOOME) {
295f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /* Let ourselves know that we tried to throw an OOM
296f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * error in the normal way in case we run out of
297f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * memory trying to allocate it inside dvmThrowException().
298f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
299f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            self->throwingOOME = true;
300f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
301f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /* Don't include a description string;
302f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * one fewer allocation.
303f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
304d27f3cf3e7b373487f39e035fc4b55168d55c454Dan Bornstein            dvmThrowOutOfMemoryError(NULL);
305f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
306f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /*
307f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * This thread has already tried to throw an OutOfMemoryError,
308f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * which probably means that we're running out of memory
309f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * while recursively trying to throw.
310f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             *
311f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * To avoid any more allocation attempts, "throw" a pre-built
312f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * OutOfMemoryError object (which won't have a useful stack trace).
313f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             *
314f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * Note that since this call can't possibly allocate anything,
315f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * we don't care about the state of self->throwingOOME
316f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * (which will usually already be set).
317f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
318f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            dvmSetException(self, gDvm.outOfMemoryObj);
319f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
320f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /* We're done with the possible recursion.
321f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
322f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        self->throwingOOME = false;
323f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
324f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
325f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
326f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
327f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Allocate storage on the GC heap.  We guarantee 8-byte alignment.
328f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
329f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * The new storage is zeroed out.
330f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
331f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Note that, in rare cases, this could get called while a GC is in
332f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * progress.  If a non-VM thread tries to attach itself through JNI,
333f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * it will need to allocate some objects.  If this becomes annoying to
334f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * deal with, we can block it at the source, but holding the allocation
335f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * mutex should be enough.
336f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
337f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * In rare circumstances (JNI AttachCurrentThread) we can be called
338f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * from a non-VM thread.
339f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
340f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Use ALLOC_DONT_TRACK when we either don't want to track an allocation
341f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * (because it's being done for the interpreter "new" operation and will
342f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * be part of the root set immediately) or we can't (because this allocation
343f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * is for a brand new thread).
344f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
345f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Returns NULL and throws an exception on failure.
346f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
347f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * TODO: don't do a GC if the debugger thinks all threads are suspended
348f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
349f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid* dvmMalloc(size_t size, int flags)
350f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
351f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    void *ptr;
352f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
353f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmLockHeap();
354f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
355f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* Try as hard as possible to allocate some memory.
356f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
3576343bd071555458d0cb071f2eaf15b59b36771bfCarl Shapiro    ptr = tryMalloc(size);
3586343bd071555458d0cb071f2eaf15b59b36771bfCarl Shapiro    if (ptr != NULL) {
359f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /* We've got the memory.
360f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
361f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (gDvm.allocProf.enabled) {
362f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Thread* self = dvmThreadSelf();
363f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            gDvm.allocProf.allocCount++;
364f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            gDvm.allocProf.allocSize += size;
365f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (self != NULL) {
366f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                self->allocProf.allocCount++;
367f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                self->allocProf.allocSize += size;
368f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
369f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
370f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    } else {
371f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /* The allocation failed.
372f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
373f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
374f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (gDvm.allocProf.enabled) {
375f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Thread* self = dvmThreadSelf();
376f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            gDvm.allocProf.failedAllocCount++;
377f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            gDvm.allocProf.failedAllocSize += size;
378f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (self != NULL) {
379f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                self->allocProf.failedAllocCount++;
380f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                self->allocProf.failedAllocSize += size;
381f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
382f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
383f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
384f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
385f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmUnlockHeap();
386f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
387f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (ptr != NULL) {
388f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
389d4f78d3a764e6aa8f7174c78f537c016dac7f7ecBarry Hayes         * If caller hasn't asked us not to track it, add it to the
390d4f78d3a764e6aa8f7174c78f537c016dac7f7ecBarry Hayes         * internal tracking list.
391f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
392d4f78d3a764e6aa8f7174c78f537c016dac7f7ecBarry Hayes        if ((flags & ALLOC_DONT_TRACK) == 0) {
393fc75f3ed87b55d625b6054e18645da5cbdba31c6Carl Shapiro            dvmAddTrackedAlloc((Object*)ptr, NULL);
394f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
395f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    } else {
396c3b92b26df6416d3179e865adccb283ee4170ab1Ben Cheng        /*
397f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * The allocation failed; throw an OutOfMemoryError.
398f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
399f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        throwOOME();
400f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
401f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
402f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return ptr;
403f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
404f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
405f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
406f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Returns true iff <obj> points to a valid allocated object.
407f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
408f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbool dvmIsValidObject(const Object* obj)
409f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
410f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* Don't bother if it's NULL or not 8-byte aligned.
411f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
4126343bd071555458d0cb071f2eaf15b59b36771bfCarl Shapiro    if (obj != NULL && ((uintptr_t)obj & (8-1)) == 0) {
413f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /* Even if the heap isn't locked, this shouldn't return
414f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * any false negatives.  The only mutation that could
415f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * be happening is allocation, which means that another
416f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * thread could be in the middle of a read-modify-write
417f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * to add a new bit for a new object.  However, that
418f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * RMW will have completed by the time any other thread
419f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * could possibly see the new pointer, so there is no
420f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * danger of dvmIsValidObject() being called on a valid
421f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * pointer whose bit isn't set.
422f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         *
423f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Freeing will only happen during the sweep phase, which
424f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * only happens while the heap is locked.
425f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
4266343bd071555458d0cb071f2eaf15b59b36771bfCarl Shapiro        return dvmHeapSourceContains(obj);
427f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
428f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return false;
429f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
430f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
431f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectsize_t dvmObjectSizeInHeap(const Object *obj)
432f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
4336343bd071555458d0cb071f2eaf15b59b36771bfCarl Shapiro    return dvmHeapSourceChunkSize(obj);
434f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
435f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
4361e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapirostatic void verifyRootsAndHeap()
437962adba4e5db286a36bc8024f5c023bcf6f29312Barry Hayes{
438106c5fd9745a47d663e28217f3dd5ac48f606f81Carl Shapiro    dvmVerifyRoots();
439106c5fd9745a47d663e28217f3dd5ac48f606f81Carl Shapiro    dvmVerifyBitmap(dvmHeapSourceGetLiveBits());
440962adba4e5db286a36bc8024f5c023bcf6f29312Barry Hayes}
441962adba4e5db286a36bc8024f5c023bcf6f29312Barry Hayes
442962adba4e5db286a36bc8024f5c023bcf6f29312Barry Hayes/*
443f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Initiate garbage collection.
444f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
445f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * NOTES:
446f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * - If we don't hold gDvm.threadListLock, it's possible for a thread to
447f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *   be added to the thread list while we work.  The thread should NOT
448f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *   start executing, so this is only interesting when we start chasing
449f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *   thread stacks.  (Before we do so, grab the lock.)
450f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
451f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * We are not allowed to GC when the debugger has suspended the VM, which
452f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * is awkward because debugger requests can cause allocations.  The easiest
453f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * way to enforce this is to refuse to GC on an allocation made by the
454f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * JDWP thread -- we have to expand the heap or fail.
455f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
456cc6f5118d19bae06cb80841386a0c95f24616a65Carl Shapirovoid dvmCollectGarbageInternal(const GcSpec* spec)
457f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
458f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    GcHeap *gcHeap = gDvm.gcHeap;
45989cf125cd95a7df3a713cb3d3d39a033304e474cJeff Brown    u4 gcEnd = 0;
4607aa9563279627b2ff5413bc895381fc170df9f12Doug Kwan    u4 rootStart = 0 , rootEnd = 0;
4617aa9563279627b2ff5413bc895381fc170df9f12Doug Kwan    u4 dirtyStart = 0, dirtyEnd = 0;
462570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro    size_t numObjectsFreed, numBytesFreed;
463570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro    size_t currAllocated, currFootprint;
464570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro    size_t percentFree;
465cc6f5118d19bae06cb80841386a0c95f24616a65Carl Shapiro    int oldThreadPriority = INT_MAX;
466f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
467f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* The heap lock must be held.
468f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
469f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
470f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (gcHeap->gcRunning) {
47160fc806b679a3655c228b4093058c59941a49cfeDan Bornstein        LOGW_HEAP("Attempted recursive GC");
472f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return;
473f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
47403f3b1394cc8421d125fd00455858944f0e9808dCarl Shapiro
475f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gcHeap->gcRunning = true;
476f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
47703f3b1394cc8421d125fd00455858944f0e9808dCarl Shapiro    rootStart = dvmGetRelativeTimeMsec();
47889cf125cd95a7df3a713cb3d3d39a033304e474cJeff Brown    dvmSuspendAllThreads(SUSPEND_FOR_GC);
479f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
480ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro    /*
481ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro     * If we are not marking concurrently raise the priority of the
482ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro     * thread performing the garbage collection.
483f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
484cc6f5118d19bae06cb80841386a0c95f24616a65Carl Shapiro    if (!spec->isConcurrent) {
485e6c0ef210ee6c62cf4c63d50c04f451d5fa505f5Elliott Hughes        oldThreadPriority = os_raiseThreadPriority();
486f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
487962adba4e5db286a36bc8024f5c023bcf6f29312Barry Hayes    if (gDvm.preVerify) {
4886c5dd93d6b41d85f54c45816120081654ed2cbd8Carl Shapiro        LOGV_HEAP("Verifying roots and heap before GC");
4896c5dd93d6b41d85f54c45816120081654ed2cbd8Carl Shapiro        verifyRootsAndHeap();
490962adba4e5db286a36bc8024f5c023bcf6f29312Barry Hayes    }
491962adba4e5db286a36bc8024f5c023bcf6f29312Barry Hayes
492f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmMethodTraceGCBegin();
493f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
494f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* Set up the marking context.
495f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
496cc6f5118d19bae06cb80841386a0c95f24616a65Carl Shapiro    if (!dvmHeapBeginMarkStep(spec->isPartial)) {
49760fc806b679a3655c228b4093058c59941a49cfeDan Bornstein        LOGE_HEAP("dvmHeapBeginMarkStep failed; aborting");
49899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        dvmAbort();
49999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    }
500f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
501f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* Mark the set of objects that are strongly reachable from the roots.
502f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
503f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    LOGD_HEAP("Marking...");
504f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmHeapMarkRootSet();
505f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
506f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* dvmHeapScanMarkedObjects() will build the lists of known
507f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * instances of the Reference classes.
508f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
509ce87bfed41bbe4248b2770fb1a90f34b2518f6faCarl Shapiro    assert(gcHeap->softReferences == NULL);
510ce87bfed41bbe4248b2770fb1a90f34b2518f6faCarl Shapiro    assert(gcHeap->weakReferences == NULL);
511ce87bfed41bbe4248b2770fb1a90f34b2518f6faCarl Shapiro    assert(gcHeap->finalizerReferences == NULL);
512ce87bfed41bbe4248b2770fb1a90f34b2518f6faCarl Shapiro    assert(gcHeap->phantomReferences == NULL);
513ce87bfed41bbe4248b2770fb1a90f34b2518f6faCarl Shapiro    assert(gcHeap->clearedReferences == NULL);
514f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
515cc6f5118d19bae06cb80841386a0c95f24616a65Carl Shapiro    if (spec->isConcurrent) {
516ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro        /*
517ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro         * Resume threads while tracing from the roots.  We unlock the
518ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro         * heap to allow mutator threads to allocate from free space.
519ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro         */
520b2714082bad44fde247920b9280c1b40c4979c3aBen Cheng        dvmClearCardTable();
521ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro        dvmUnlockHeap();
522ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro        dvmResumeAllThreads(SUSPEND_FOR_GC);
52389cf125cd95a7df3a713cb3d3d39a033304e474cJeff Brown        rootEnd = dvmGetRelativeTimeMsec();
524ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro    }
525ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro
526f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* Recursively mark any objects that marked objects point to strongly.
527f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * If we're not collecting soft references, soft-reachable
528f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * objects will also be marked.
529f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
530f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    LOGD_HEAP("Recursing...");
531b2714082bad44fde247920b9280c1b40c4979c3aBen Cheng    dvmHeapScanMarkedObjects();
532f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
533cc6f5118d19bae06cb80841386a0c95f24616a65Carl Shapiro    if (spec->isConcurrent) {
534ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro        /*
535ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro         * Re-acquire the heap lock and perform the final thread
536ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro         * suspension.
537ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro         */
53889cf125cd95a7df3a713cb3d3d39a033304e474cJeff Brown        dirtyStart = dvmGetRelativeTimeMsec();
539ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro        dvmLockHeap();
540ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro        dvmSuspendAllThreads(SUSPEND_FOR_GC);
541ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro        /*
542ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro         * As no barrier intercepts root updates, we conservatively
543ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro         * assume all roots may be gray and re-mark them.
544ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro         */
545106c5fd9745a47d663e28217f3dd5ac48f606f81Carl Shapiro        dvmHeapReMarkRootSet();
546ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro        /*
5475ba39376c5b7a5878f234a689a51c74783583b4bCarl Shapiro         * With the exception of reference objects and weak interned
5485ba39376c5b7a5878f234a689a51c74783583b4bCarl Shapiro         * strings, all gray objects should now be on dirty cards.
5495ba39376c5b7a5878f234a689a51c74783583b4bCarl Shapiro         */
5505ba39376c5b7a5878f234a689a51c74783583b4bCarl Shapiro        if (gDvm.verifyCardTable) {
5515ba39376c5b7a5878f234a689a51c74783583b4bCarl Shapiro            dvmVerifyCardTable();
5525ba39376c5b7a5878f234a689a51c74783583b4bCarl Shapiro        }
5535ba39376c5b7a5878f234a689a51c74783583b4bCarl Shapiro        /*
554ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro         * Recursively mark gray objects pointed to by the roots or by
555ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro         * heap objects dirtied during the concurrent mark.
556ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro         */
557106c5fd9745a47d663e28217f3dd5ac48f606f81Carl Shapiro        dvmHeapReScanMarkedObjects();
558ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro    }
559ec805eaed940e40212e85b58b163c7649feaca56Carl Shapiro
560e8ef2b53866b01fb5a8e73ea867c934777aec57eCarl Shapiro    /*
561e8ef2b53866b01fb5a8e73ea867c934777aec57eCarl Shapiro     * All strongly-reachable objects have now been marked.  Process
562e8ef2b53866b01fb5a8e73ea867c934777aec57eCarl Shapiro     * weakly-reachable objects discovered while tracing.
563f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
564cc6f5118d19bae06cb80841386a0c95f24616a65Carl Shapiro    dvmHeapProcessReferences(&gcHeap->softReferences,
565ae188c676c681e47a93ade7fdf0144099b470e03Carl Shapiro                             spec->doPreserve == false,
566e8ef2b53866b01fb5a8e73ea867c934777aec57eCarl Shapiro                             &gcHeap->weakReferences,
5673475f9cdb47a6d6f8ad2ce49bbc3af46bca92f09Carl Shapiro                             &gcHeap->finalizerReferences,
568e8ef2b53866b01fb5a8e73ea867c934777aec57eCarl Shapiro                             &gcHeap->phantomReferences);
569f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
5708881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro#if defined(WITH_JIT)
5718881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro    /*
5728881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro     * Patching a chaining cell is very cheap as it only updates 4 words. It's
5738881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro     * the overhead of stopping all threads and synchronizing the I/D cache
5748881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro     * that makes it expensive.
5758881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro     *
5768881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro     * Therefore we batch those work orders in a queue and go through them
5778881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro     * when threads are suspended for GC.
5788881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro     */
5798881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro    dvmCompilerPerformSafePointChecks();
580f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#endif
5818881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro
582f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    LOGD_HEAP("Sweeping...");
583f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
5848881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro    dvmHeapSweepSystemWeaks();
5858881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro
5868881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro    /*
5878881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro     * Live objects have a bit set in the mark bitmap, swap the mark
5888881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro     * and live bitmaps.  The sweep can proceed concurrently viewing
5898881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro     * the new live bitmap as the old mark bitmap, and vice versa.
5908881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro     */
5918881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro    dvmHeapSourceSwapBitmaps();
5928881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro
5938881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro    if (gDvm.postVerify) {
5948881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro        LOGV_HEAP("Verifying roots and heap after GC");
5958881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro        verifyRootsAndHeap();
5968881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro    }
5978881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro
598cc6f5118d19bae06cb80841386a0c95f24616a65Carl Shapiro    if (spec->isConcurrent) {
5998881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro        dvmUnlockHeap();
6008881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro        dvmResumeAllThreads(SUSPEND_FOR_GC);
60189cf125cd95a7df3a713cb3d3d39a033304e474cJeff Brown        dirtyEnd = dvmGetRelativeTimeMsec();
6028881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro    }
603cc6f5118d19bae06cb80841386a0c95f24616a65Carl Shapiro    dvmHeapSweepUnmarkedObjects(spec->isPartial, spec->isConcurrent,
604570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro                                &numObjectsFreed, &numBytesFreed);
605f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    LOGD_HEAP("Cleaning up...");
606f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmHeapFinishMarkStep();
607cc6f5118d19bae06cb80841386a0c95f24616a65Carl Shapiro    if (spec->isConcurrent) {
6088881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro        dvmLockHeap();
6098881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro    }
610f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
611f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    LOGD_HEAP("Done.");
612f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
613f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* Now's a good time to adjust the heap size, since
614f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * we know what our utilization is.
615f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
616f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * This doesn't actually resize any memory;
617f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * it just lets the heap grow more when necessary.
618f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
619e7bdd8b8c6f3aae552b333d0bd9664ef5e63f0a0Carl Shapiro    dvmHeapSourceGrowForUtilization();
620f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
621570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro    currAllocated = dvmHeapSourceGetValue(HS_BYTES_ALLOCATED, NULL, 0);
622570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro    currFootprint = dvmHeapSourceGetValue(HS_FOOTPRINT, NULL, 0);
623570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro
624f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmMethodTraceGCEnd();
625962adba4e5db286a36bc8024f5c023bcf6f29312Barry Hayes    LOGV_HEAP("GC finished");
626962adba4e5db286a36bc8024f5c023bcf6f29312Barry Hayes
627f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gcHeap->gcRunning = false;
628f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
629962adba4e5db286a36bc8024f5c023bcf6f29312Barry Hayes    LOGV_HEAP("Resuming threads");
630f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
631cc6f5118d19bae06cb80841386a0c95f24616a65Carl Shapiro    if (spec->isConcurrent) {
632ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro        /*
633ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro         * Wake-up any threads that blocked after a failed allocation
634ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro         * request.
635ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro         */
636ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro        dvmBroadcastCond(&gDvm.gcHeapCond);
637ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro    }
638ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro
639cc6f5118d19bae06cb80841386a0c95f24616a65Carl Shapiro    if (!spec->isConcurrent) {
6408881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro        dvmResumeAllThreads(SUSPEND_FOR_GC);
64189cf125cd95a7df3a713cb3d3d39a033304e474cJeff Brown        dirtyEnd = dvmGetRelativeTimeMsec();
642cc6f5118d19bae06cb80841386a0c95f24616a65Carl Shapiro        /*
643cc6f5118d19bae06cb80841386a0c95f24616a65Carl Shapiro         * Restore the original thread scheduling priority if it was
644cc6f5118d19bae06cb80841386a0c95f24616a65Carl Shapiro         * changed at the start of the current garbage collection.
645cc6f5118d19bae06cb80841386a0c95f24616a65Carl Shapiro         */
646cc6f5118d19bae06cb80841386a0c95f24616a65Carl Shapiro        if (oldThreadPriority != INT_MAX) {
647e6c0ef210ee6c62cf4c63d50c04f451d5fa505f5Elliott Hughes            os_lowerThreadPriority(oldThreadPriority);
648256fc159a267859c18e11e1d15fd7d97a59757c6San Mehat        }
649f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
650f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
651ce87bfed41bbe4248b2770fb1a90f34b2518f6faCarl Shapiro    /*
652ce87bfed41bbe4248b2770fb1a90f34b2518f6faCarl Shapiro     * Move queue of pending references back into Java.
653ce87bfed41bbe4248b2770fb1a90f34b2518f6faCarl Shapiro     */
654ce87bfed41bbe4248b2770fb1a90f34b2518f6faCarl Shapiro    dvmEnqueueClearedReferences(&gDvm.gcHeap->clearedReferences);
655ce87bfed41bbe4248b2770fb1a90f34b2518f6faCarl Shapiro
65689cf125cd95a7df3a713cb3d3d39a033304e474cJeff Brown    gcEnd = dvmGetRelativeTimeMsec();
657570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro    percentFree = 100 - (size_t)(100.0f * (float)currAllocated / currFootprint);
658cc6f5118d19bae06cb80841386a0c95f24616a65Carl Shapiro    if (!spec->isConcurrent) {
65903f3b1394cc8421d125fd00455858944f0e9808dCarl Shapiro        u4 markSweepTime = dirtyEnd - rootStart;
66089cf125cd95a7df3a713cb3d3d39a033304e474cJeff Brown        u4 gcTime = gcEnd - rootStart;
661570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro        bool isSmall = numBytesFreed > 0 && numBytesFreed < 1024;
66289cf125cd95a7df3a713cb3d3d39a033304e474cJeff Brown        ALOGD("%s freed %s%zdK, %d%% free %zdK/%zdK, paused %ums, total %ums",
663cc6f5118d19bae06cb80841386a0c95f24616a65Carl Shapiro             spec->reason,
664570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro             isSmall ? "<" : "",
665570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro             numBytesFreed ? MAX(numBytesFreed / 1024, 1) : 0,
666570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro             percentFree,
667570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro             currAllocated / 1024, currFootprint / 1024,
66889cf125cd95a7df3a713cb3d3d39a033304e474cJeff Brown             markSweepTime, gcTime);
66903f3b1394cc8421d125fd00455858944f0e9808dCarl Shapiro    } else {
6708881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro        u4 rootTime = rootEnd - rootStart;
6718881a8098e259a1faf392d20c1fefc1ee4a63b20Carl Shapiro        u4 dirtyTime = dirtyEnd - dirtyStart;
67289cf125cd95a7df3a713cb3d3d39a033304e474cJeff Brown        u4 gcTime = gcEnd - rootStart;
673570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro        bool isSmall = numBytesFreed > 0 && numBytesFreed < 1024;
67489cf125cd95a7df3a713cb3d3d39a033304e474cJeff Brown        ALOGD("%s freed %s%zdK, %d%% free %zdK/%zdK, paused %ums+%ums, total %ums",
675cc6f5118d19bae06cb80841386a0c95f24616a65Carl Shapiro             spec->reason,
676570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro             isSmall ? "<" : "",
677570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro             numBytesFreed ? MAX(numBytesFreed / 1024, 1) : 0,
678570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro             percentFree,
679570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro             currAllocated / 1024, currFootprint / 1024,
68089cf125cd95a7df3a713cb3d3d39a033304e474cJeff Brown             rootTime, dirtyTime, gcTime);
681570942c26061692dc30e3c8ac1dc28d50170ef6aCarl Shapiro    }
682f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (gcHeap->ddmHpifWhen != 0) {
68360fc806b679a3655c228b4093058c59941a49cfeDan Bornstein        LOGD_HEAP("Sending VM heap info to DDM");
684f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dvmDdmSendHeapInfo(gcHeap->ddmHpifWhen, false);
685f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
686f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (gcHeap->ddmHpsgWhen != 0) {
68760fc806b679a3655c228b4093058c59941a49cfeDan Bornstein        LOGD_HEAP("Dumping VM heap to DDM");
688f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dvmDdmSendHeapSegments(false, false);
689f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
690f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (gcHeap->ddmNhsgWhen != 0) {
69160fc806b679a3655c228b4093058c59941a49cfeDan Bornstein        LOGD_HEAP("Dumping native heap to DDM");
692f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dvmDdmSendHeapSegments(false, true);
693f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
694f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
695f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
69658aa611bb6f45eab669644b97e77165eb417458aAndy McFadden/*
69758aa611bb6f45eab669644b97e77165eb417458aAndy McFadden * If the concurrent GC is running, wait for it to finish.  The caller
69858aa611bb6f45eab669644b97e77165eb417458aAndy McFadden * must hold the heap lock.
69958aa611bb6f45eab669644b97e77165eb417458aAndy McFadden *
70058aa611bb6f45eab669644b97e77165eb417458aAndy McFadden * Note: the second dvmChangeStatus() could stall if we were in RUNNING
70158aa611bb6f45eab669644b97e77165eb417458aAndy McFadden * on entry, and some other thread has asked us to suspend.  In that
70258aa611bb6f45eab669644b97e77165eb417458aAndy McFadden * case we will be suspended with the heap lock held, which can lead to
70358aa611bb6f45eab669644b97e77165eb417458aAndy McFadden * deadlock if the other thread tries to do something with the managed heap.
70458aa611bb6f45eab669644b97e77165eb417458aAndy McFadden * For example, the debugger might suspend us and then execute a method that
70558aa611bb6f45eab669644b97e77165eb417458aAndy McFadden * allocates memory.  We can avoid this situation by releasing the lock
70658aa611bb6f45eab669644b97e77165eb417458aAndy McFadden * before self-suspending.  (The developer can work around this specific
70758aa611bb6f45eab669644b97e77165eb417458aAndy McFadden * situation by single-stepping the VM.  Alternatively, we could disable
70858aa611bb6f45eab669644b97e77165eb417458aAndy McFadden * concurrent GC when the debugger is attached, but that might change
70958aa611bb6f45eab669644b97e77165eb417458aAndy McFadden * behavior more than is desirable.)
71058aa611bb6f45eab669644b97e77165eb417458aAndy McFadden *
71158aa611bb6f45eab669644b97e77165eb417458aAndy McFadden * This should not be a problem in production, because any GC-related
71258aa611bb6f45eab669644b97e77165eb417458aAndy McFadden * activity will grab the lock before issuing a suspend-all.  (We may briefly
71358aa611bb6f45eab669644b97e77165eb417458aAndy McFadden * suspend when the GC thread calls dvmUnlockHeap before dvmResumeAllThreads,
71458aa611bb6f45eab669644b97e77165eb417458aAndy McFadden * but there's no risk of deadlock.)
71558aa611bb6f45eab669644b97e77165eb417458aAndy McFadden */
7161e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapirovoid dvmWaitForConcurrentGcToComplete()
717ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro{
718ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro    Thread *self = dvmThreadSelf();
719ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro    assert(self != NULL);
72089cf125cd95a7df3a713cb3d3d39a033304e474cJeff Brown    u4 start = dvmGetRelativeTimeMsec();
721039167e7894ae16880f51fa0b4d44316318aae1eCarl Shapiro    while (gDvm.gcHeap->gcRunning) {
722039167e7894ae16880f51fa0b4d44316318aae1eCarl Shapiro        ThreadStatus oldStatus = dvmChangeStatus(self, THREAD_VMWAIT);
723039167e7894ae16880f51fa0b4d44316318aae1eCarl Shapiro        dvmWaitCond(&gDvm.gcHeapCond, &gDvm.gcHeapLock);
724039167e7894ae16880f51fa0b4d44316318aae1eCarl Shapiro        dvmChangeStatus(self, oldStatus);
725039167e7894ae16880f51fa0b4d44316318aae1eCarl Shapiro    }
72689cf125cd95a7df3a713cb3d3d39a033304e474cJeff Brown    u4 end = dvmGetRelativeTimeMsec();
72789cf125cd95a7df3a713cb3d3d39a033304e474cJeff Brown    ALOGD("WAIT_FOR_CONCURRENT_GC blocked %ums", end - start);
728ec47e2e081dcd43dca10d5e2c6856f73e94b0460Carl Shapiro}
729