Heap Usage in Cacao
The following is a short list of all the places where Cacao allocates memory regions on the heap. It contains the source-file and the line of code which calls the allocator.
Heap can contain the following collectable structures:
These objects are known to the GarbageCollector and should be collected. Once considered dead, the memory will be set free automatically.
- Java Objects starting with java_objectheader in builtin_new():
vm/builtin.c: o = heap_allocate(c->instancesize, c->flags & ACC_CLASS_HAS_POINTERS,
- Java Arrays starting with java_arrayheader in builtin_newarray():
vm/builtin.c: a = heap_allocate(actualsize, (desc->arraytype == ARRAYTYPE_OBJECT), NULL);
- Java Arrays as clones in Java_java_lang_VMObject_clone():
native/vm/java_lang_VMObject.c: heap_allocate(size, (desc->arraytype == ARRAYTYPE_OBJECT), NULL);
- Reference Table containing localref_table in jni_init_localref_table():
The local ref table keeps objects alive, so it must either be on the heap or taken into the root set. (See http://java.sun.com/j2se/1.4.2/docs/guide/jni/spec/design.html#wp1242)
native/jni.c: lrt = GCNEW(localref_table); native/jni.c: nlrt = GCMNEW(u1, sizeof(localref_table) + additionalrefs * SIZEOF_VOID_P);
- Stacktrace Buffer containing stacktracebuffer in stacktrace_fillInStackTrace():
This is on the heap as it has an indeterminate (possibly long) lifetime and is referenced by a VMThrowable object. We could turn this into a proper java object (probably an array) to make the GC's life easier.
Access must be very fast, at least for the stacktraces in dump memory, maybe also for the ones copied to the heap.
This buffer is now wraped by an stacktracecontainer, which actually presents itself as a Byte-Array to the GC. This wrapping is only done when placed onto the Heap and undone when used out of the Heap, so it should not harm our performance. It gets allocated by builtin_newarray_byte(), so all fields get initialized. Look below to get a glance on the struct.
vm/jit/stacktrace.c: gcstb = GCNEW(stacktracebuffer); vm/jit/stacktrace.c: gcstb->entries = GCMNEW(stacktrace_entry, stb->used); typedef struct stacktracecontainer { java_arrayheader header; /* default array header for the GC */ struct stacktracebuffer stb; /* let entries point to data below */ stacktrace_entry data[1]; /* the actual array of entries */ } stacktracecontainer; - Interpreter Stack in threads_startup_thread():
Does this one really have to be on the heap? How can i collect this?
It is on the heap, because objects reachable from the interpreter stack are alive. Another option would be to add the whole interpreter stack to the root set. The interpreter stack will be a problem for an exact GC, as the stack slots (called "cells" in the interpreter) are untyped.
We will need stack type analysis for the interpreter, because the GC must know the types of stack slots and local variables at GC points and at call sites. A good starting point to get this info is the new stack-based verifier.
vm/vm.c: intrp_main_stack = GCMNEW(u1, opt_stacksize);
Uncollectable regions of the Heap acting as root set:
- Class Info containing classinfo in class_create_classinfo():
classinfos are used as java.lang.Class objects, and they refer to other classes, and to the defining classloader. (ClassLoaders are java objects). classinfos are special regarding GC, as all the classes defined by the same loader must be unloaded atomically.
vm/class.c: c = GCNEW_UNCOLLECTABLE(classinfo, 1);
- Field Infos contain array of fieldinfo in load_class_from_classbuffer():
For static fields the fieldinfo contains the value of the field. This is the reason that fieldinfos must be in the root set. The fieldinfo structs themselves are not managed in any way. (They are freed with the classinfo, except we never free classinfos, currently.)
Methods don't contain any references, they are allocated with MNEW. If we implement class unloading, methods will be freed together with their class.
The fieldinfo structures were moved off the stack for the exact GC.
vm/loader.c: c->fields = GCNEW_UNCOLLECTABLE(fieldinfo, c->fieldscount);
Unappropriate use of Heap:
These calls are specific to the BoehmGC and unapproptiate for the new GarbageCollector.
This strange GCNEW was added by twisti IIRC in order to trigger some Boehm setup code. It is Boehm-specific, so do not worry about it.
vm/signal.c: (void) GCNEW(u1); vm/jit/mips/linux/md-os.c: heap_allocate(1, 0, NULL); vm/jit/mips/irix/md-os.c: heap_allocate(1, 0, NULL);
Unknown use of Heap:
Hmm, what do these do? One never knows!
vm/classcache.c: classes = GCMNEW(classinfo*, class_count);
The one above is JVMTI related. Probably this line was written by Martin. I see no particular reason to use the heap here. Could be changed, or turned into a proper java array, if it needs to be on the heap (classinfos are valid java objects).
native/jvmti/jvmti.c: *libname = GCMNEW(char, i); native/jvmti/jvmti.c: *libname = GCMNEW(char, len); native/jvmti/cacaodbg.c: dbgcom = heap_allocate(sizeof(cacaodbgcommunication),true,NULL); native/jvmti/jvmti.c: ll->next = heap_allocate(sizeof(jvmtiEventModeLL),true,NULL); native/jvmti/jvmti.c: heap_allocate(sizeof(jthread*)* (*threads_count_ptr),true,NULL); native/jvmti/jvmti.c: info_ptr->name=(char*)heap_allocate(sizeof(char)*(utf_bytes(name)+1),true,NULL); native/jvmti/jvmti.c: heap_allocate(sizeof(java_objectheader*) * i, true, NULL); native/jvmti/jvmti.c: *groups_ptr = heap_allocate(sizeof(jthreadGroup*)*x,true,NULL); native/jvmti/jvmti.c: info_ptr->name=heap_allocate(size*sizeof(char),true,NULL); native/jvmti/jvmti.c: heap_allocate(sizeof(jthread)*(*thread_count_ptr),true,NULL); native/jvmti/jvmti.c: heap_allocate(sizeof(jthreadGroup)*(*group_count_ptr),true,NULL); native/jvmti/jvmti.c: *mem_ptr = heap_allocate(sizeof(size),true,NULL); native/jvmti/jvmti.c: heap_allocate(sizeof(char) * native/jvmti/jvmti.c: *source_name_ptr = (char*) heap_allocate(sizeof(char)* size,true,NULL); native/jvmti/jvmti.c: heap_allocate(sizeof(jmethodID) * (*method_count_ptr),true,NULL); native/jvmti/jvmti.c: heap_allocate(sizeof(jfieldID) * (*field_count_ptr),true,NULL); native/jvmti/jvmti.c: heap_allocate(sizeof(jclass*) * (*interface_count_ptr),true,NULL); native/jvmti/jvmti.c: *name_ptr = (char*) heap_allocate(sizeof(char)* size,true,NULL); native/jvmti/jvmti.c: *signature_ptr = (char*) heap_allocate(sizeof(char)* size,true,NULL); native/jvmti/jvmti.c: heap_allocate(sizeof(char) * (utf_bytes(m->name)+1),true,NULL); native/jvmti/jvmti.c: heap_allocate(sizeof(char)*(utf_bytes(m->descriptor)+1),true,NULL); native/jvmti/jvmti.c: *table_ptr = (jvmtiLineNumberEntry*) heap_allocate( native/jvmti/jvmti.c: *bytecodes_ptr = (unsigned char*)heap_allocate(m->jcodelength,true,NULL); native/jvmti/jvmti.c: heap_allocate(sizeof(jvmtiStackInfo) * thread_count, true, NULL); native/jvmti/jvmti.c: heap_allocate(sizeof(jvmtiFrameInfo) * max_frame_count,true,NULL); native/jvmti/jvmti.c: tls = env->tls = heap_allocate(sizeof(jvmtiThreadLocalStorage),true,NULL); native/jvmti/jvmti.c: tls->next = heap_allocate(sizeof(jvmtiThreadLocalStorage),true,NULL); native/jvmti/jvmti.c: _Jv_env->env = (void*)heap_allocate(sizeof(jniNativeInterface),true,NULL); native/jvmti/jvmti.c: heap_allocate(sizeof(jniNativeInterface),true,NULL); native/jvmti/jvmti.c:#define COPY_RESPONSE(name_ptr,str) *name_ptr = (char*) heap_allocate(sizeof(str),true,NULL); \ native/jvmti/jvmti.c: *property_ptr = heap_allocate(sizeof(char*) * (*count_ptr) ,true,NULL); native/jvmti/jvmti.c: *property_ptr[i] = heap_allocate(sizeof(char*) * strlen (ch),true,NULL); native/jvmti/jvmti.c: *value_ptr = heap_allocate(sizeof(char*) * strlen (ch),true,NULL); native/jvmti/jvmti.c: envs = heap_allocate(sizeof(environment),true,NULL); native/jvmti/jvmti.c: env->next = heap_allocate(sizeof(environment),true,NULL); native/jvmti/jvmti.c: env->env = heap_allocate(sizeof(struct jvmtiEnv_struct),true,NULL);