You are missing to understand that the actual garbage collection may happen not when you expected (by whatever reason), but it may happen some time later. I cannot believe it is not garbage-collected at all. I think, it happens, but later. You did not mention it in your description though.
The operation of GC is driven by the reachability
of objects. The actual call of the object destructors and the act of reclaiming memory cannot be predicted bu the application (by the way, this is the reason why destructors are rarely written in the typical .NET applications, usually this is not needed and can created some problems of race conditions
type), but it happens when some object becomes unreachable
By the way, this is not so trivial criterion as you might think. For example, if object A references object B, object B references object C, and C reference A, this cyclic dependency does not prevent GC from figuring out that all objects should be garbage-collected if there are no other referenced to them. This is easy to check up by a simple experiment.
You can find the detail of reachability and garbage collection here: http://en.wikipedia.org/wiki/Garbage_collection_%28computer_science%29
Now, you should not think that such thing as memory leak
is impossible in a memory-managed system like CLR. It is quite possible, but the problem here is understanding what is a memory leak. For further detail, please see my past answers on this and related topics:
Garbage collectotion takes care of all the memory management
deferring varirable inside the loop can cuase memory leak?
Best way to get rid of a public static List Causing an Out of Memory
Memory management in MDI forms