Back in 2000 when the CLR was first shown it's generational garbage collector was fairly cutting edge. But it's weaknesses show it's age - and it desperately needs updating.
Here's an example of just one of the ways the current GC (.Net 3.5) doesn't work:
A .Net process with a number of threads has just saved a large amount of data to a database. All of these threads could potentially allocate memory which causes a GC collection. However, saving the data to the database is a fairly long operation and thus the data gets promoted into the GC's generation 2.
After saving the data, the .Net process waits until it's instructed to do some more work. However, because a large amount of data has been promoted into Gen2, it just sits there until sufficient new allocations cause a Gen2 GC collection. The problem is that if no new work happens for a long time (hours), these unreachable objects take up (virtual) address space. Yes, NT will swap it out to disk as virtual memory. But it's still there.
The GC really needs a timer, which periodically checks if no GCs have happened recently and the process has consumed very little CPU, then perform a Gen2 collection.
Aside: Does anyone know how to trigger a GC.Collect() on a process from a different process, or from inside WinDbg? One of the problems with WinDbg/SOS is figuring out just which objects are reachable - you would have to !gcroot every possible object just to figure out which are the reachable ones.