2 * Copyright (C) 2008 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 * Garbage-collecting memory allocator.
20 #include "alloc/Heap.h"
21 #include "alloc/HeapInternal.h"
22 #include "alloc/HeapSource.h"
24 #if WITH_HPROF && WITH_HPROF_STACK
25 #include "hprof/Hprof.h"
30 * Initialize the GC universe.
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.
35 bool dvmGcStartup(void)
37 dvmInitMutex(&gDvm.gcHeapLock);
39 return dvmHeapStartup();
43 * Post-zygote heap initialization, including starting
44 * the HeapWorker thread.
46 bool dvmGcStartupAfterZygote(void)
48 if (!dvmHeapWorkerStartup()) {
51 return dvmHeapStartupAfterZygote();
55 * Shutdown the threads internal to the garbage collector.
57 void dvmGcThreadShutdown(void)
59 dvmHeapWorkerShutdown();
60 dvmHeapThreadShutdown();
66 void dvmGcShutdown(void)
68 //TODO: grab and destroy the lock
73 * Do any last-minute preparation before we call fork() for the first time.
75 bool dvmGcPreZygoteFork(void)
77 return dvmHeapSourceStartupBeforeFork();
81 * Create a "stock instance" of an exception class.
83 static Object* createStockException(const char* descriptor, const char* msg)
85 Thread* self = dvmThreadSelf();
86 StringObject* msgStr = NULL;
91 /* find class, initialize if necessary */
92 clazz = dvmFindSystemClass(descriptor);
94 LOGE("Unable to find %s\n", descriptor);
98 init = dvmFindDirectMethodByDescriptor(clazz, "<init>",
99 "(Ljava/lang/String;)V");
101 LOGE("Unable to find String-arg constructor for %s\n", descriptor);
105 obj = dvmAllocObject(clazz, ALLOC_DEFAULT);
112 msgStr = dvmCreateStringFromCstr(msg);
113 if (msgStr == NULL) {
114 LOGW("Could not allocate message string \"%s\"\n", msg);
115 dvmReleaseTrackedAlloc(obj, self);
121 dvmCallMethod(self, init, obj, &unused, msgStr);
122 if (dvmCheckException(self)) {
123 dvmReleaseTrackedAlloc((Object*) msgStr, self);
124 dvmReleaseTrackedAlloc(obj, self);
128 dvmReleaseTrackedAlloc((Object*) msgStr, self); // okay if msgStr NULL
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.
137 * We can't do this during the initial startup because we need to execute
140 bool dvmCreateStockExceptions(void)
143 * Pre-allocate some throwables. These need to be explicitly added
144 * to the GC's root set (see dvmHeapMarkRootSet()).
146 gDvm.outOfMemoryObj = createStockException("Ljava/lang/OutOfMemoryError;",
147 "[memory exhausted]");
148 dvmReleaseTrackedAlloc(gDvm.outOfMemoryObj, NULL);
149 gDvm.internalErrorObj = createStockException("Ljava/lang/InternalError;",
151 dvmReleaseTrackedAlloc(gDvm.internalErrorObj, NULL);
152 gDvm.noClassDefFoundErrorObj =
153 createStockException("Ljava/lang/NoClassDefFoundError;",
155 dvmReleaseTrackedAlloc(gDvm.noClassDefFoundErrorObj, NULL);
157 if (gDvm.outOfMemoryObj == NULL || gDvm.internalErrorObj == NULL ||
158 gDvm.noClassDefFoundErrorObj == NULL)
160 LOGW("Unable to create stock exceptions\n");
169 * Create an instance of the specified class.
171 * Returns NULL and throws an exception on failure.
173 Object* dvmAllocObject(ClassObject* clazz, int flags)
177 assert(dvmIsClassInitialized(clazz) || dvmIsClassInitializing(clazz));
179 if (IS_CLASS_FLAG_SET(clazz, CLASS_ISFINALIZABLE)) {
180 flags |= ALLOC_FINALIZABLE;
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);
190 dvmTrackAllocation(clazz, clazz->objectSize);
197 * Create a copy of an object, for Object.clone().
199 * We use the size actually allocated, rather than obj->clazz->objectSize,
200 * because the latter doesn't work for array objects.
202 Object* dvmCloneObject(Object* obj)
208 assert(dvmIsValidObject(obj));
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".
214 assert(obj->clazz != gDvm.classJavaLangClass);
216 if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISFINALIZABLE))
217 flags = ALLOC_DEFAULT | ALLOC_FINALIZABLE;
219 flags = ALLOC_DEFAULT;
221 if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISARRAY)) {
222 size = dvmArrayObjectSize((ArrayObject *)obj);
224 size = obj->clazz->objectSize;
227 copy = dvmMalloc(size, flags);
230 #if WITH_HPROF && WITH_HPROF_STACK
231 hprofFillInStackTrace(copy);
232 dvmTrackAllocation(obj->clazz, size);
235 memcpy(copy, obj, size);
236 DVM_LOCK_INIT(©->lock);
237 dvmWriteBarrierObject(copy);
244 * Track an object that was allocated internally and isn't yet part of the
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.
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().
253 void dvmAddTrackedAlloc(Object* obj, Thread* self)
256 self = dvmThreadSelf();
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);
268 * Stop tracking an object.
270 * We allow attempts to delete NULL "obj" so that callers don't have to wrap
271 * calls with "if != NULL".
273 void dvmReleaseTrackedAlloc(Object* obj, Thread* self)
279 self = dvmThreadSelf();
280 assert(self != NULL);
282 if (!dvmRemoveFromReferenceTable(&self->internalLocalRefTable,
283 self->internalLocalRefTable.table, obj))
285 LOGE("threadid=%d: failed to remove %p from internal ref table\n",
286 self->threadId, obj);
293 * Explicitly initiate garbage collection.
295 void dvmCollectGarbage(bool collectSoftReferences)
298 while (gDvm.gcHeap->gcRunning) {
299 dvmWaitForConcurrentGcToComplete();
301 dvmCollectGarbageInternal(collectSoftReferences, GC_EXPLICIT);
306 const ClassObject *clazz;
310 static void countInstancesOfClassCallback(void *ptr, void *arg)
312 CountContext *ctx = arg;
313 const Object *obj = ptr;
316 if (obj->clazz == ctx->clazz) {
321 size_t dvmCountInstancesOfClass(const ClassObject *clazz)
323 CountContext ctx = { clazz, 0 };
324 HeapBitmap *bitmap = dvmHeapSourceGetLiveBits();
326 dvmHeapBitmapWalk(bitmap, countInstancesOfClassCallback, &ctx);
331 static void countAssignableInstancesOfClassCallback(void *ptr, void *arg)
333 CountContext *ctx = arg;
334 const Object *obj = ptr;
337 if (dvmInstanceof(obj->clazz, ctx->clazz)) {
342 size_t dvmCountAssignableInstancesOfClass(const ClassObject *clazz)
344 CountContext ctx = { clazz, 0 };
345 HeapBitmap *bitmap = dvmHeapSourceGetLiveBits();
347 dvmHeapBitmapWalk(bitmap, countAssignableInstancesOfClassCallback, &ctx);