Isn't "removing it from your collection" synonymous with "set all references to it to null"?
No. The .NET gc doesn't use a reference counting system. Its all based on roots and if an object is reachable.
Say object A references object B which references object C. Just for fun, object C references object A.
a-->b-->c ^ | |_______|
These were all local to a function, but we've now exited out of that function. We can no longer reach any of them. Next time a garbage collection happens, all 3 objects are eligable for collection since they are no longer rooted.
We created 3 objects, with cyclic references even.... but nothing had to be explicitly nulled or deleted.
in real-time programming you need things to happen exactly when and how you want. No "waiting for the garbage collection to kick in".
As far as games or graphics programming goes, what does it matter if a sprite/bullet/whatever is deleted at precisely the moment you stop using it? How will that negatively effect the execution of your program?
I mean really think about it. Your program isn't going to run slower or incorrectly because you have dead objects sitting in the heap.
it introduces a lot of complexity in how objects are created/destroyed.
Like in the first example, just drop your garbage on the floor and be done with it..it'll get cleaned up. Thats one of the beautiful things about .NET.
The garbage collector is pretty efficient in practice. Its self tuning, and allocation based. When you create new objects and fill up more of the heap, the more likely it will kick into action. But if you're not allocating anything -- the gc is essentially asleep.
So someone will point out -- "but you're always creating new objects!" Which is true, but you have to remember that in .NET a good portion of what you work with are valuetype's, like int, float, or user defined structs. These all live on the stack, or are embedded into other objects. They have none of the overhead involved with garbage collection.
Is the gc perfect? Not quite ;)
In general, any managed object will get cleaned up as needed, but theres a gotcha when it comes to delegates and events. Those *can* leak.
The gc has no say over unmanaged code, so alot of the time when you interact with native libraries, you have to implement the Dispose pattern for deterministic clean up.
When it comes to doing work with pointers, you have a slight hassle of having to pin objects in place, so the gc wont move your object, and invalidate your pointers.