Alloc.cpp revision c6d2470eec726ae0ad95e4fd2d9d7da7cb2cdcba
1/* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16/* 17 * Garbage-collecting memory allocator. 18 */ 19#include "Dalvik.h" 20#include "alloc/Heap.h" 21#include "alloc/HeapInternal.h" 22#include "alloc/HeapSource.h" 23 24/* 25 * Initialize the GC universe. 26 * 27 * We're currently using a memory-mapped arena to keep things off of the 28 * main heap. This needs to be replaced with something real. 29 */ 30bool dvmGcStartup(void) 31{ 32 dvmInitMutex(&gDvm.gcHeapLock); 33 34 return dvmHeapStartup(); 35} 36 37/* 38 * Post-zygote heap initialization, including starting 39 * the HeapWorker thread. 40 */ 41bool dvmGcStartupAfterZygote(void) 42{ 43 return dvmHeapStartupAfterZygote(); 44} 45 46/* 47 * Shutdown the threads internal to the garbage collector. 48 */ 49void dvmGcThreadShutdown(void) 50{ 51 dvmHeapThreadShutdown(); 52} 53 54/* 55 * Shut the GC down. 56 */ 57void dvmGcShutdown(void) 58{ 59 //TODO: grab and destroy the lock 60 dvmHeapShutdown(); 61} 62 63/* 64 * Do any last-minute preparation before we call fork() for the first time. 65 */ 66bool dvmGcPreZygoteFork(void) 67{ 68 return dvmHeapSourceStartupBeforeFork(); 69} 70 71bool dvmGcStartupClasses(void) 72{ 73 { 74 const char *klassName = "Ljava/lang/ref/ReferenceQueueThread;"; 75 ClassObject *klass = dvmFindSystemClass(klassName); 76 if (klass == NULL) { 77 return false; 78 } 79 const char *methodName = "startReferenceQueue"; 80 Method *method = dvmFindDirectMethodByDescriptor(klass, methodName, "()V"); 81 if (method == NULL) { 82 return false; 83 } 84 Thread *self = dvmThreadSelf(); 85 assert(self != NULL); 86 JValue unusedResult; 87 dvmCallMethod(self, method, NULL, &unusedResult); 88 } 89 { 90 const char *klassName = "Ljava/lang/FinalizerThread;"; 91 ClassObject *klass = dvmFindSystemClass(klassName); 92 if (klass == NULL) { 93 return false; 94 } 95 const char *methodName = "startFinalizer"; 96 Method *method = dvmFindDirectMethodByDescriptor(klass, methodName, "()V"); 97 if (method == NULL) { 98 return false; 99 } 100 Thread *self = dvmThreadSelf(); 101 assert(self != NULL); 102 JValue unusedResult; 103 dvmCallMethod(self, method, NULL, &unusedResult); 104 } 105 106 return true; 107} 108 109/* 110 * Create a "stock instance" of an exception class. 111 */ 112static Object* createStockException(const char* descriptor, const char* msg) 113{ 114 Thread* self = dvmThreadSelf(); 115 StringObject* msgStr = NULL; 116 ClassObject* clazz; 117 Method* init; 118 Object* obj; 119 120 /* find class, initialize if necessary */ 121 clazz = dvmFindSystemClass(descriptor); 122 if (clazz == NULL) { 123 LOGE("Unable to find %s\n", descriptor); 124 return NULL; 125 } 126 127 init = dvmFindDirectMethodByDescriptor(clazz, "<init>", 128 "(Ljava/lang/String;)V"); 129 if (init == NULL) { 130 LOGE("Unable to find String-arg constructor for %s\n", descriptor); 131 return NULL; 132 } 133 134 obj = dvmAllocObject(clazz, ALLOC_DEFAULT); 135 if (obj == NULL) 136 return NULL; 137 138 if (msg == NULL) { 139 msgStr = NULL; 140 } else { 141 msgStr = dvmCreateStringFromCstr(msg); 142 if (msgStr == NULL) { 143 LOGW("Could not allocate message string \"%s\"\n", msg); 144 dvmReleaseTrackedAlloc(obj, self); 145 return NULL; 146 } 147 } 148 149 JValue unused; 150 dvmCallMethod(self, init, obj, &unused, msgStr); 151 if (dvmCheckException(self)) { 152 dvmReleaseTrackedAlloc((Object*) msgStr, self); 153 dvmReleaseTrackedAlloc(obj, self); 154 return NULL; 155 } 156 157 dvmReleaseTrackedAlloc((Object*) msgStr, self); // okay if msgStr NULL 158 return obj; 159} 160 161/* 162 * Create some "stock" exceptions. These can be thrown when the system is 163 * too screwed up to allocate and initialize anything, or when we don't 164 * need a meaningful stack trace. 165 * 166 * We can't do this during the initial startup because we need to execute 167 * the constructors. 168 */ 169bool dvmCreateStockExceptions(void) 170{ 171 /* 172 * Pre-allocate some throwables. These need to be explicitly added 173 * to the GC's root set (see dvmHeapMarkRootSet()). 174 */ 175 gDvm.outOfMemoryObj = createStockException("Ljava/lang/OutOfMemoryError;", 176 "[memory exhausted]"); 177 dvmReleaseTrackedAlloc(gDvm.outOfMemoryObj, NULL); 178 gDvm.internalErrorObj = createStockException("Ljava/lang/InternalError;", 179 "[pre-allocated]"); 180 dvmReleaseTrackedAlloc(gDvm.internalErrorObj, NULL); 181 gDvm.noClassDefFoundErrorObj = 182 createStockException("Ljava/lang/NoClassDefFoundError;", 183 "[generic]"); 184 dvmReleaseTrackedAlloc(gDvm.noClassDefFoundErrorObj, NULL); 185 186 if (gDvm.outOfMemoryObj == NULL || gDvm.internalErrorObj == NULL || 187 gDvm.noClassDefFoundErrorObj == NULL) 188 { 189 LOGW("Unable to create stock exceptions\n"); 190 return false; 191 } 192 193 return true; 194} 195 196 197/* 198 * Create an instance of the specified class. 199 * 200 * Returns NULL and throws an exception on failure. 201 */ 202Object* dvmAllocObject(ClassObject* clazz, int flags) 203{ 204 Object* newObj; 205 206 assert(clazz != NULL); 207 assert(dvmIsClassInitialized(clazz) || dvmIsClassInitializing(clazz)); 208 209 /* allocate on GC heap; memory is zeroed out */ 210 newObj = (Object*)dvmMalloc(clazz->objectSize, flags); 211 if (newObj != NULL) { 212 DVM_OBJECT_INIT(newObj, clazz); 213 dvmTrackAllocation(clazz, clazz->objectSize); /* notify DDMS */ 214 } 215 216 return newObj; 217} 218 219/* 220 * Create a copy of an object, for Object.clone(). 221 * 222 * We use the size actually allocated, rather than obj->clazz->objectSize, 223 * because the latter doesn't work for array objects. 224 */ 225Object* dvmCloneObject(Object* obj, int flags) 226{ 227 ClassObject* clazz; 228 Object* copy; 229 size_t size; 230 231 assert(dvmIsValidObject(obj)); 232 clazz = obj->clazz; 233 234 /* Class.java shouldn't let us get here (java.lang.Class is final 235 * and does not implement Clonable), but make extra sure. 236 * A memcpy() clone will wreak havoc on a ClassObject's "innards". 237 */ 238 assert(!dvmIsTheClassClass(clazz)); 239 240 if (IS_CLASS_FLAG_SET(clazz, CLASS_ISARRAY)) { 241 size = dvmArrayObjectSize((ArrayObject *)obj); 242 } else { 243 size = clazz->objectSize; 244 } 245 246 copy = (Object*)dvmMalloc(size, flags); 247 if (copy == NULL) 248 return NULL; 249 250 /* We assume that memcpy will copy obj by words. */ 251 memcpy(copy, obj, size); 252 DVM_LOCK_INIT(©->lock); 253 dvmWriteBarrierObject(copy); 254 255 /* Mark the clone as finalizable if appropriate. */ 256 if (IS_CLASS_FLAG_SET(clazz, CLASS_ISFINALIZABLE)) { 257 dvmSetFinalizable(copy); 258 } 259 260 dvmTrackAllocation(clazz, size); /* notify DDMS */ 261 262 return copy; 263} 264 265 266/* 267 * Track an object that was allocated internally and isn't yet part of the 268 * VM root set. 269 * 270 * We could do this per-thread or globally. If it's global we don't have 271 * to do the thread lookup but we do have to synchronize access to the list. 272 * 273 * "obj" must not be NULL. 274 * 275 * NOTE: "obj" is not a fully-formed object; in particular, obj->clazz will 276 * usually be NULL since we're being called from dvmMalloc(). 277 */ 278void dvmAddTrackedAlloc(Object* obj, Thread* self) 279{ 280 if (self == NULL) 281 self = dvmThreadSelf(); 282 283 assert(obj != NULL); 284 assert(self != NULL); 285 if (!dvmAddToReferenceTable(&self->internalLocalRefTable, obj)) { 286 LOGE("threadid=%d: unable to add %p to internal ref table\n", 287 self->threadId, obj); 288 dvmDumpThread(self, false); 289 dvmAbort(); 290 } 291} 292 293/* 294 * Stop tracking an object. 295 * 296 * We allow attempts to delete NULL "obj" so that callers don't have to wrap 297 * calls with "if != NULL". 298 */ 299void dvmReleaseTrackedAlloc(Object* obj, Thread* self) 300{ 301 if (obj == NULL) 302 return; 303 304 if (self == NULL) 305 self = dvmThreadSelf(); 306 assert(self != NULL); 307 308 if (!dvmRemoveFromReferenceTable(&self->internalLocalRefTable, 309 self->internalLocalRefTable.table, obj)) 310 { 311 LOGE("threadid=%d: failed to remove %p from internal ref table\n", 312 self->threadId, obj); 313 dvmAbort(); 314 } 315} 316 317 318/* 319 * Explicitly initiate garbage collection. 320 */ 321void dvmCollectGarbage(void) 322{ 323 if (gDvm.disableExplicitGc) { 324 return; 325 } 326 dvmLockHeap(); 327 dvmWaitForConcurrentGcToComplete(); 328 dvmCollectGarbageInternal(GC_EXPLICIT); 329 dvmUnlockHeap(); 330} 331 332typedef struct { 333 const ClassObject *clazz; 334 size_t count; 335} CountContext; 336 337static void countInstancesOfClassCallback(void *ptr, void *arg) 338{ 339 CountContext *ctx = (CountContext *)arg; 340 const Object *obj = (const Object *)ptr; 341 342 assert(ctx != NULL); 343 if (obj->clazz == ctx->clazz) { 344 ctx->count += 1; 345 } 346} 347 348size_t dvmCountInstancesOfClass(const ClassObject *clazz) 349{ 350 CountContext ctx = { clazz, 0 }; 351 dvmLockHeap(); 352 HeapBitmap *bitmap = dvmHeapSourceGetLiveBits(); 353 dvmHeapBitmapWalk(bitmap, countInstancesOfClassCallback, &ctx); 354 dvmUnlockHeap(); 355 return ctx.count; 356} 357 358static void countAssignableInstancesOfClassCallback(void *ptr, void *arg) 359{ 360 CountContext *ctx = (CountContext *)arg; 361 const Object *obj = (const Object *)ptr; 362 363 assert(ctx != NULL); 364 if (obj->clazz != NULL && dvmInstanceof(obj->clazz, ctx->clazz)) { 365 ctx->count += 1; 366 } 367} 368 369size_t dvmCountAssignableInstancesOfClass(const ClassObject *clazz) 370{ 371 CountContext ctx = { clazz, 0 }; 372 dvmLockHeap(); 373 HeapBitmap *bitmap = dvmHeapSourceGetLiveBits(); 374 dvmHeapBitmapWalk(bitmap, countAssignableInstancesOfClassCallback, &ctx); 375 dvmUnlockHeap(); 376 return ctx.count; 377} 378 379bool dvmIsHeapAddress(void *address) 380{ 381 return dvmHeapSourceContainsAddress(address); 382} 383