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