Home | History | Annotate | Download | only in alloc
      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(&copy->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