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