Handling GC allocated objects in C As part of an effort to improve our GC, we need to keep track precisely of where objects are stored, so we can incrementally move from the current conservative GC to a more advanced precise and moving GC. Previously, all global C variables were considered GC roots, but this makes the GC less efficient and increases the chances false references are found to GC memory, hence retaining more memory than needed. We need to tell the GC that some object is supposed to be kept alive as if it was referenced in a global variable. For Mono embedders ------------------ In C#, if you say: class T { static object o; } Any object which is stored in `o' is considered to be alive -- it will not be collected. `o' is a member of the root set for the GC. However, in C code, this is not the case. If you have: static MonoObject* o = NULL; The object in `o' will *NOT* be scanned. If you need to store an object in a C variable and prevent it from being collected, you need to acquire a GC handle for it. guint32 handle = mono_gchandle_new (my_object, TRUE); TRUE means the object will be pinned, so it won't move in memory when we'll use a moving GC. You can access the MonoObject* referenced by a handle with: MonoObject* obj = mono_gchandle_get_target (handle); When you don't need the handle anymore you need to call: mono_gchandle_free (handle); Note that if you assign a new object to the C var, you need to get a new handle, it's not enough to store a new object in the C var. So code that looked like this: static MonoObject* o = NULL; ... o = mono_object_new (...); /* use o */ ... /* when done to allow the GC to collect o */ o = NULL; should now be changed to: static guint32 o_handle; ... MonoObject *o = mono_object_new (...); o_handle = mono_gchandle_new (o, TRUE); /* use o or mono_gchandle_get_target (o_handle) */ ... /* when done to allow the GC to collect o */ mono_gchandle_free (o_handle); For Mono runtime developers --------------------------- There are two kinds of static vars used to store pointers to GC memory that we need to consider: *) objects *) other memory chunks allocated with GC_MALLOC(). Objects should be dealt with the GC handle support as detailed above. Other items should register the static pointer as an area to be considered part of the root set with the following: static gpointer my_gc_data = NULL; ... MONO_GC_REGISTER_ROOT (my_gc_data); my_gc_data = GC_MALLOC (...); Note that this registration is not necessary for *LOCAL* variables, as they are stored on the stack. It is only necessary for global variables, as they are not a part of the GC's root set. Once you have done the MONO_GC_REGISTER_ROOT, the variable is just like a static variable in C#. To keep an object alive, you have the variable reference the GC memory, to remove the reference, set the variable to NULL. As we prepare the code for a precise GC, GC_MALLOC () will not be used anymore in this way in most cases: we'll have a mechanism to specify exactly where references to GC memory is stored. [The rest of this file is useless, just kept until the switchover of the internals is complete.] Mono Internal Audit ------------------- Until now, we have been able to store gc references in variables. This means we must audit the source code for where this happens, and ensure the GC knows the right roots. Because this is a change from previous behavior, an audit must be done to check for any incorrect uses. Basically, we need to check all variables that contain GC allocated objects. This includes MonoObject*'s, any other pointer to a managed type, and MonoGHashTable's. Any such variable must either 1) be added as a root -or- 2) only hold values that are referenced elsewhere The status of the audit is below: metadata -------- appdomain.c No variables which can contain GC allocated data assembly.c No variables which can contain GC allocated data class.c No variables which can contain GC allocated data debug-helpers.c No variables which can contain GC allocated data debug-mono-symfile.c No variables decimal.c No variables which can contain GC allocated data domain.c static MonoGHashTable * appdomains_list = NULL; This has been added as a root static MonoDomain *mono_root_domain = NULL; this is added to the `appdomains_list' hashtable which keeps the reference No other variables contain GC allocated data. environment.c No variables which can contain GC allocated data exception.c No variables. file-io.c No variables filewatcher.c No variablesNo other variables contain GC allocated data. gc.c static MonoThread *gc_thread; MonoThread*'s are taken care of by threads.c static gpointer *gc_handles = NULL; static guint8 *gc_handle_types = NULL; These were added as roots No other variables contain GC allocated data. icall.c No variables which can contain GC allocated data image.c No variables which can contain GC allocated data loader.c No variables which can contain GC allocated data locales.c No variables marshal.c static MonoGHashTable *wrapper_hash; Added as a root static MonoString *string_dummy = NULL; Added as a root No other variables contain GC allocated data. mempool.c No variables metadata.c No variables which can contain GC allocated data monitor.c No variables mono-config.c No variables which can contain GC allocated data mono-debug.c No variables which can contain GC allocated data mono-debug-debugger.c static MonoObject *last_exception = NULL; Added as a root No other variables contain GC allocated data. mono-endian.c No variables monosn.c Not compiled object.c static MonoThread *main_thread; Taken care of by threads.c No other variables contain GC allocated data. opcodes.c No variables which can contain GC allocated data pedump.c No variables which canMONO_GC_REGISTER_ROOT (my_object); contain GC allocated data process.c No variables which can contain GC allocated data profiler.c No variables which can contain GC allocated data rand.c No variables rawbuffer.c No variables which can contain GC allocated data reflection.c No variables which can contain GC allocated data security.c No variables. socket-io.c No variables which can contain GC allocated data string-icalls.c No variables sysmath.c No variables threadpool.c static MonoGHashTable *ares_htable = NULL; Added as a root No other variables contain GC allocated data. threads.c static MonoGHashTable *threads=NULL Added as a root. This variable keeps a reference to all threads, so it covers other files. No other variables contain GC allocated data. typedef.c No variables unicode.c No variables which can contain GC allocated data verify.c No variables which can contain GC allocated data utils/ ------ monobitset.c No variables which can contain GC allocated data mono-codeman.c No variables which can contain GC allocated data mono-hash.c static MonoGHashNode *node_free_list = NULL; added as a root No other variables contain GC allocated data. mono-logger.c No variables which can contain GC allocated data mono-math.c No variables which can contain GC allocated data mono-md5.c No variables which can contain GC allocated data mono-sha1.c No variables which can contain GC allocated data mono-uri.c No variables which can contain GC allocated data strenc.c No variables which can contain GC allocated data strtod.c No variables which can contain GC allocated data interp/ -------- interp.c static MonoGHashTable *method_pointer_hash = NULL; Added as a root No other variables contain GC allocated data. main.c No variables which can contain GC allocated data mintops.c No variables which can contain GC allocated data transform.c No variables which can contain GC allocated data mini/ ----- abcremoval.c No variables which can contain GC allocated data aot.c static MonoGHashTable *aot_modules; Added as root No other variables contain GC allocated data. cfold.c No variables which can contain GC allocated data cprop.c Not compiled debug-mini.c No variables. dominators.c No variables driver.c No variables which can contain GC allocated data exceptions-ppc.c No variables which can contain GC allocated data exceptions-s390.c No variables which can contain GC allocated data exceptions-sparc.c No variables which can contain GC allocated data exceptions-x86.c No variables which can contain GC allocated data genmdesc.c Not part of mini graph.c No variables which can contain GC allocated data helpers.c No variables which can contain GC allocated data inssel.c No variables which can contain GC allocated data jit-icalls.c No variables linear-scan.c No variables liveness.c No variables main.c No variables mini.c No variables which can contain GC allocated data mini-exceptions.c No variables which can contain GC allocated data mini-ppc.c No variables which can contain GC allocated data mini-s390.c No variables which can contain G C allocated data mini-sparc.c No variables which can contain GC allocated data mini-x86.c No variables which can contain GC allocated data regalloc.c No variables which can contain GC allocated data ssa.c No variables which can contain GC allocated data trace.c No variables which can contain GC allocated data tramp-ppc.c No variables which can contain GC allocated data tramp-s390.c No variables which can contain GC allocated data tramp-sparc.c No variables which can contain GC allocated data tramp-x86.c No variables which can contain GC allocated data io-layer/ --------- atomic.c No variables which can contain GC allocated data context.c No variables which can contain GC allocated data critical-sections.c No variables which can contain GC allocated data daemon.c No variables which can contain GC allocated data daemon-messages.c No variables which can contain GC allocated data error.c No variables which can contain GC allocated data events.c No variables which can contain GC allocated data handles.c No variables which can contain GC allocated data io.c No variables which can contain GC allocated data io-layer-dummy.c No variables which can contain GC allocated data misc.c No variables which can contain GC allocated data mono-mutex.c No variables which can contain GC allocated data mutexes.c No variables which can contain GC allocated data processes.c No variables which can contain GC allocated data security.c No variables which can contain GC allocated data semaphores.c No variables which can contain GC allocated data shared.c No variables which can contain GC allocated data sockets.c No variables which can contain GC allocated data system.c No variables which can contain GC allocated data threads.c static MonoGHashTable *tls_gc_hash = NULL; added as a root No other variables contain GC allocated data. timed-thread.c No variables which can contain GC allocated data timefuncs.c No variables which can contain GC allocated data wait.c No variables which can contain GC allocated data