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