Yes, a very good point. I've thought of two ways to solve that problem:
- The "easy way out" would be to check whether a struct has any ref type fields and then treat it as a ref type (convert it to a class, which should be trivial). Not ideal since the point of using structs might be to put them in an array. But this could be the initial "solution".
- A better but more difficult solution: Any structs that have ref type fields also get the same hard-coded functions to manage their pointers just like classes get (Mark and UpdatePointer). Then when the structs get initialized as locals in a function, a pointer to them is pushed onto the virtual stack. Now when the GC walks the stack, those structs will also have their pointer management functions called. For arrays, they can be treated as structs (not boxed), but the array class that holds structs (or ref types), will know how to call each of its array items' pointer management functions.
That should never happen, if an object is not reachable then it's garbage and it will be collected. If you pass a GC pointer to native code then you know what you need to do: use "fixed" or GCHandle to prevent the GC from moving/collecting the object.
Are you sure? Let's say the class has a method like this:
That is certainly not "illegal" code and the compiler can't guard against it. Now if the original ref to MyClass goes out of scope, then it is no longer reachable and it will be GC'd (and hence someRefObjField won't be reachable either and will be GC'd).
Watch out that moving objects and updating pointers can be extremly tricky. I'm not talking about finding the roots which can be itself a problem, I'm talking about how can you update pointers in an efficient way. One thing is clear: you can't move one object and then call UpdatePointers on all the other objects in the heap, that has quadratic complexity.
Yes, and I was wondering about that too. Not sure if it would be faster to send a Dictionary<,> of changed pointers or not. I was thinking that I might just move one class at a time, hence making the GC "incremental". On a microcontroller it might be more important for the GC to not lock everything up for long periods of times instead of absolute performance. There is often somewhat of a "realtime" nature to microcontrollers with its hardware interrupts etc.
Since evildictaitor mentioned it: have you considered using Boehm GC instead?http://en.wikipedia.org/wiki/Boehm_garbage_collector
I'll take a look, thanks.
Hmm, not sure what CultureInfo has to do with List<>. Maybe the Sort method uses it somehow. Since you wrote that code you should be able to modify it to log some information about why a particular type has been included, right?
It possibly came in via one of the exception classes. I'll need to create substitutes for all of those too, so once I do, it might end up filtering out a lot of the unneeded stuff.
If I understand correctly now you're including all the methods of an used type, you may consider excluding methods that are never called.
That is what I'm already doing with my "call graph". I start at the Assembly.EntryPoint and look at all the IL instructions for any method calls. Any types that get referenced along the way gets added too. This process is repeated recursively for all methods found within the IL.
What I'm suggesting is improving on this process by stripping the fields out of types that were never referenced during all of the code paths. So if a class has a member field called SomeHugeClass, but the code path never references it, it can be safely removed it altogether. How else is it going to be referenced (other than via the static constructors which I'l treat in the same way)? Of course this makes reflection impossible but that is fine, I think reflection can be left out for now - it is a microcontroller after all.