a575963da9
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
101 lines
3.2 KiB
Plaintext
101 lines
3.2 KiB
Plaintext
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. This mechanism is now available with the new GC,
|
|
see usages of mono_gc_alloc_fixed (), mono_gc_register_root () and
|
|
mono_gc_make_descr_from_bitmap().
|
|
See also docs/precise-gc for additional info.
|
|
|