2010-04-20 Rodrigo Kumpera <rkumpera@novell.com>
[mono-project.git] / docs / precise-gc
blobcf0f733639d1646d2ceaad65e2d98107bcc1a817
1 While the Boehm GC is quite good, we need to move to a 
2 precise, generational GC for better performance and smaller
3 memory usage (no false-positives memory retentions with big
4 allocations).
6 The first working implementation is committed in metadata/sgen-gc.c
7 as of May, 2006. This is a two-generations moving collector and it is
8 currently used to shake out all the issues in the runtime that need to
9 be fixed in order to support precise generational and moving collectors.
11 The two main issues are:
12 1) identify as precisely as possible all the pointers to managed objects
13 2) insert write barriers to be able to account for pointers in the old
14 generation pointing to objects in the newer generations
16 Point 1 is mostly complete. The runtime can register additional roots
17 with the GC as needed and it provides to the GC precise info on the
18 objects layout. In particular with the new precise GC it is not possible to
19 store GC-allocated memory in IntPtr or UIntPtr fields (in fact, the new GC
20 can allocate only objects and not GC-tracked untyped blobs of memory
21 as the Boehm GC can do). Precise info is tracked also for static fields.
22 What is currently missing here is:
23 *) precise info for ThreadStatic and ContextStatic storage (this also requires
24 better memory management for these sub-heaps)
25 *) precise info for HANDLE_NORMAL gc handles
26 *) precise info for thread stacks (this requires storing the info about
27 managed stack frames along with the jitted code for a method and doing the
28 stack walk for the active threads, considering conservatively the unmanaged
29 stack frames and precisely the managed ones. mono_jit_info_table_find () must
30 be made lock-free for this to work). Precise type info must be maintained
31 for all the local variables. Precise type info should be maintained also
32 for registers.
33 Note that this is not a correctness issue, but a performance one. The more
34 pointers to objects we can deal with precisely, the more effective the GC
35 will be, since it will be able to move the objects. The first two todo items
36 are mostly trivial, while handling precisely the thread stacks is complex to
37 implement and to test and it has a cpu and memory use runtime penalty.
38 In practice we need to be able to describe to the GC _all_ the memory
39 locations that can hold a pointer to a managed object and we must tell it also
40 if that location can contain:
41 *) a pointer to the start of an object or NULL (typically a field of an object)
42 *) a pinning pointer to an object (typically the result of the fixed statment in C#)
43 *) a pointer to the managed heap or to other locations (a typical stack location)
44 Since we need to provide to the GC all the locations it's not possible anymore to
45 store any object in unmanaged memory if it is not explicitly pinned for the entire
46 time the object is stored there. With the Boehm GC this was possible if the object
47 was kept alive in some way, but with the new GC it is not valid anymore, because
48 objects can move: the object will be kept alive because of the other reference, but the
49 pointer in unmanaged memory won't be updated to the new location where the object
50 has been moved.
52 Most of the work for inserting write barrier calls is already done as well,
53 but there may be still bugs in this area. In particular for it to work,
54 the correct IL opcodes must be used when storing an object in a field or
55 array element (most of the marshal.c code needs to be reviewed to use 
56 stind.ref instead of stind.i/stind.u when needed). When this is done, the
57 JIT will take care of automatically inserting the write barriers.
58 What the JIT does automatically for managed code, must be done manually
59 in the runtime C code that deals with storing fields in objects and arrays
60 or otherwise any operation that could change a pointer in the old generation
61 to point to an object in the new generation. Sample cases are as follows:
63 *) when using C structs that map to managed objects the following macro
64 must be used to store an object in a field (the macro must not be used
65 when storing non-objects and it should not be used when storing NULL values):
67         MONO_OBJECT_SETREF(obj,fieldname,value)
68 where obj is the pointer to the object, fieldname is the name of the field in
69 the C struct and value is a MonoObject*. Note that obj must be a correctly
70 typed pointer to a struct that embeds MonoObject as the first field and
71 have fieldname as a field.
73 *) when setting the element of an array of references to an object, use the
74 following macro:
76         mono_array_setref (array,index,value)
78 *) when copying a number of references from an array to another:
80         mono_array_memcpy_refs (dest,destidx,src,srcidx,count)
82 *) when copying a struct that may containe reference fields, use:
84         void mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
86 *) when it is unknown if a pointer points to the stack or to the heap and an
87 object needs to be stored through it, use:
89         void mono_gc_wbarrier_generic_store (gpointer ptr, MonoObject* value)
91 Note that the support for write barriers in the runtime could be
92 used to enable also the generational features of the Boehm GC.
94 Some more documentation on the new GC is available at:
95 http://www.mono-project.com/Compacting_GC