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 #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(&copy->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