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"
23 #include "alloc/HeapWorker.h"
26 * Initialize the GC universe.
28 * We're currently using a memory-mapped arena to keep things off of the
29 * main heap. This needs to be replaced with something real.
31 bool dvmGcStartup(void)
33 dvmInitMutex(&gDvm.gcHeapLock);
35 return dvmHeapStartup();
39 * Post-zygote heap initialization, including starting
40 * the HeapWorker thread.
42 bool dvmGcStartupAfterZygote(void)
44 if (!dvmHeapWorkerStartup()) {
47 return dvmHeapStartupAfterZygote();
51 * Shutdown the threads internal to the garbage collector.
53 void dvmGcThreadShutdown(void)
55 dvmHeapWorkerShutdown();
56 dvmHeapThreadShutdown();
62 void dvmGcShutdown(void)
64 //TODO: grab and destroy the lock
69 * Do any last-minute preparation before we call fork() for the first time.
71 bool dvmGcPreZygoteFork(void)
73 return dvmHeapSourceStartupBeforeFork();
77 * Create a "stock instance" of an exception class.
79 static Object* createStockException(const char* descriptor, const char* msg)
81 Thread* self = dvmThreadSelf();
82 StringObject* msgStr = NULL;
87 /* find class, initialize if necessary */
88 clazz = dvmFindSystemClass(descriptor);
90 LOGE("Unable to find %s\n", descriptor);
94 init = dvmFindDirectMethodByDescriptor(clazz, "<init>",
95 "(Ljava/lang/String;)V");
97 LOGE("Unable to find String-arg constructor for %s\n", descriptor);
101 obj = dvmAllocObject(clazz, ALLOC_DEFAULT);
108 msgStr = dvmCreateStringFromCstr(msg);
109 if (msgStr == NULL) {
110 LOGW("Could not allocate message string \"%s\"\n", msg);
111 dvmReleaseTrackedAlloc(obj, self);
117 dvmCallMethod(self, init, obj, &unused, msgStr);
118 if (dvmCheckException(self)) {
119 dvmReleaseTrackedAlloc((Object*) msgStr, self);
120 dvmReleaseTrackedAlloc(obj, self);
124 dvmReleaseTrackedAlloc((Object*) msgStr, self); // okay if msgStr NULL
129 * Create some "stock" exceptions. These can be thrown when the system is
130 * too screwed up to allocate and initialize anything, or when we don't
131 * need a meaningful stack trace.
133 * We can't do this during the initial startup because we need to execute
136 bool dvmCreateStockExceptions(void)
139 * Pre-allocate some throwables. These need to be explicitly added
140 * to the GC's root set (see dvmHeapMarkRootSet()).
142 gDvm.outOfMemoryObj = createStockException("Ljava/lang/OutOfMemoryError;",
143 "[memory exhausted]");
144 dvmReleaseTrackedAlloc(gDvm.outOfMemoryObj, NULL);
145 gDvm.internalErrorObj = createStockException("Ljava/lang/InternalError;",
147 dvmReleaseTrackedAlloc(gDvm.internalErrorObj, NULL);
148 gDvm.noClassDefFoundErrorObj =
149 createStockException("Ljava/lang/NoClassDefFoundError;",
151 dvmReleaseTrackedAlloc(gDvm.noClassDefFoundErrorObj, NULL);
153 if (gDvm.outOfMemoryObj == NULL || gDvm.internalErrorObj == NULL ||
154 gDvm.noClassDefFoundErrorObj == NULL)
156 LOGW("Unable to create stock exceptions\n");
165 * Create an instance of the specified class.
167 * Returns NULL and throws an exception on failure.
169 Object* dvmAllocObject(ClassObject* clazz, int flags)
173 assert(clazz != NULL);
174 assert(dvmIsClassInitialized(clazz) || dvmIsClassInitializing(clazz));
176 /* allocate on GC heap; memory is zeroed out */
177 newObj = (Object*)dvmMalloc(clazz->objectSize, flags);
178 if (newObj != NULL) {
179 DVM_OBJECT_INIT(newObj, clazz);
180 dvmTrackAllocation(clazz, clazz->objectSize); /* notify DDMS */
187 * Create a copy of an object, for Object.clone().
189 * We use the size actually allocated, rather than obj->clazz->objectSize,
190 * because the latter doesn't work for array objects.
192 Object* dvmCloneObject(Object* obj, int flags)
198 assert(dvmIsValidObject(obj));
201 /* Class.java shouldn't let us get here (java.lang.Class is final
202 * and does not implement Clonable), but make extra sure.
203 * A memcpy() clone will wreak havoc on a ClassObject's "innards".
205 assert(clazz != gDvm.classJavaLangClass);
207 if (IS_CLASS_FLAG_SET(clazz, CLASS_ISARRAY)) {
208 size = dvmArrayObjectSize((ArrayObject *)obj);
210 size = clazz->objectSize;
213 copy = (Object*)dvmMalloc(size, flags);
217 /* We assume that memcpy will copy obj by words. */
218 memcpy(copy, obj, size);
219 DVM_LOCK_INIT(©->lock);
220 dvmWriteBarrierObject(copy);
222 /* Mark the clone as finalizable if appropriate. */
223 if (IS_CLASS_FLAG_SET(clazz, CLASS_ISFINALIZABLE)) {
224 dvmSetFinalizable(copy);
227 dvmTrackAllocation(clazz, size); /* notify DDMS */
234 * Track an object that was allocated internally and isn't yet part of the
237 * We could do this per-thread or globally. If it's global we don't have
238 * to do the thread lookup but we do have to synchronize access to the list.
240 * "obj" must not be NULL.
242 * NOTE: "obj" is not a fully-formed object; in particular, obj->clazz will
243 * usually be NULL since we're being called from dvmMalloc().
245 void dvmAddTrackedAlloc(Object* obj, Thread* self)
248 self = dvmThreadSelf();
251 assert(self != NULL);
252 if (!dvmAddToReferenceTable(&self->internalLocalRefTable, obj)) {
253 LOGE("threadid=%d: unable to add %p to internal ref table\n",
254 self->threadId, obj);
255 dvmDumpThread(self, false);
261 * Stop tracking an object.
263 * We allow attempts to delete NULL "obj" so that callers don't have to wrap
264 * calls with "if != NULL".
266 void dvmReleaseTrackedAlloc(Object* obj, Thread* self)
272 self = dvmThreadSelf();
273 assert(self != NULL);
275 if (!dvmRemoveFromReferenceTable(&self->internalLocalRefTable,
276 self->internalLocalRefTable.table, obj))
278 LOGE("threadid=%d: failed to remove %p from internal ref table\n",
279 self->threadId, obj);
286 * Explicitly initiate garbage collection.
288 void dvmCollectGarbage(void)
290 if (gDvm.disableExplicitGc) {
294 dvmWaitForConcurrentGcToComplete();
295 dvmCollectGarbageInternal(GC_EXPLICIT);
300 const ClassObject *clazz;
304 static void countInstancesOfClassCallback(void *ptr, void *arg)
306 CountContext *ctx = (CountContext *)arg;
307 const Object *obj = (const Object *)ptr;
310 if (obj->clazz == ctx->clazz) {
315 size_t dvmCountInstancesOfClass(const ClassObject *clazz)
317 CountContext ctx = { clazz, 0 };
319 HeapBitmap *bitmap = dvmHeapSourceGetLiveBits();
320 dvmHeapBitmapWalk(bitmap, countInstancesOfClassCallback, &ctx);
325 static void countAssignableInstancesOfClassCallback(void *ptr, void *arg)
327 CountContext *ctx = (CountContext *)arg;
328 const Object *obj = (const Object *)ptr;
331 if (obj->clazz != NULL && dvmInstanceof(obj->clazz, ctx->clazz)) {
336 size_t dvmCountAssignableInstancesOfClass(const ClassObject *clazz)
338 CountContext ctx = { clazz, 0 };
340 HeapBitmap *bitmap = dvmHeapSourceGetLiveBits();
341 dvmHeapBitmapWalk(bitmap, countAssignableInstancesOfClassCallback, &ctx);
346 bool dvmIsHeapAddress(void *address)
348 return dvmHeapSourceContainsAddress(address);