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 */ 35 bool 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 */ 46 bool 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 */ 57 void dvmGcThreadShutdown(void) 58 { 59 dvmHeapWorkerShutdown(); 60 dvmHeapThreadShutdown(); 61 } 62 63 /* 64 * Shut the GC down. 65 */ 66 void 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 */ 75 bool dvmGcPreZygoteFork(void) 76 { 77 return dvmHeapSourceStartupBeforeFork(); 78 } 79 80 /* 81 * Create a "stock instance" of an exception class. 82 */ 83 static 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 */ 140 bool 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 */ 173 Object* 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 */ 202 Object* 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 */ 253 void 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 */ 273 void 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 */ 295 void dvmCollectGarbage(bool collectSoftReferences) 296 { 297 dvmLockHeap(); 298 while (gDvm.gcHeap->gcRunning) { 299 dvmWaitForConcurrentGcToComplete(); 300 } 301 dvmCollectGarbageInternal(collectSoftReferences, GC_EXPLICIT); 302 dvmUnlockHeap(); 303 } 304 305 typedef struct { 306 const ClassObject *clazz; 307 size_t count; 308 } CountContext; 309 310 static 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 321 size_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 331 static 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 342 size_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