The dotNet garbage collector is, at it's heart, a move to another heap style
collector for the Gen0 and Gen1 heaps and a mark/sweep/compact collector for
the Gen2 heap. What this means is that the runtime keeps a list of all
known starting points for the heaps and either moves the objects to the next
heap or compacts free space out of the heap (Gen2 only). Known starting
points include, but are not limited to, global variables and the stack
frames for each thread. There are NO reference counters in the garbage
collector's managed memory. Setting an object to Nothing simply releases
the reference from the variable to the object in the heap. The problem is
that neither the VB nor the C# (obj = null
compilers is smart enough to
realize that this statement should simply be ignored and not generate code.
Since I didn't see the entire thread, I'm making an assumption that you are
coming from a VB6 background and that you are using the VS debugger and
seeing that the objects are still accessible after you are done with them.
In debug mode, the compiler internally sets a GC.KeepAlive at the end of
each method (function, sub, property) on all objects created in the current
method that are not returned by the function or property get or attached to
another object. I'm not sure the exact mechanism for this, but the end
result is that objects in debug releases are kept to the end of the method
even if they are no longer referenced, allowing you to inspect their
contents anywhere in the method. In release code, this doesn't happen and
the GC may safely collect these objects in the middle of a method.
As for the code being "too complicated" for the GC to figure out, that
simply cannot happen given that at any time during the execution of a
program, you can always identify memory that is accessible given that you
always have the system memory roots available. If an object isn't
accessible from a root, your code can no longer see it. Note that this is
only true for 100% managed code. As soon as you start calling COM objects
and DLLs outside the managed environment, you need to use the interop
libraries and sometimes the GC.KeepAlive methods to give the garbage
collector the information it needs to avoid collecting memory used to pass
data between the COM and DLL objects and the managed code. The interop and
GC.KeepAlive calls provide a method for the programmer to tell the GC that
specific objects are a known "root" for garbage collection purposes.
Mike Ober.