Unless I misunderstand the garbage collector completely, if its declared locally in a function and the function exits the reference goes to 0 which marks it to be cleaned up.
Firstly, the GC doesn't work by a reference count approach. It uses a broader approach to mark memory for release.

Secondly memory is only released when the GC has to. Which is why it appears to build up to an absolute maximum and then drops down.

It doesn't release memory immediately : it waits until it's got lots of memory to be released and then does it in one block.

Thirdly, the GC likes lots of little classes rather than a few big ones. It assumes larger classes will survive longer than smaller ones (or something like that). I've written about this before and it's one of my likes about C# : good object orientation is rewarded by faster running and smaller footprint exes than bad object orientation.

GC.Collect() has been put into the framework for the very reason that you've found : i.e. when you need to force the GC to do its garbage collection at a specific point. Personally I've never had to use it : and I've written some very large apps in my time with C# with a lot of memory allocations.

Darwen.