The Perfect Solution
Most would agree that the perfect solution to this problem would result in a system in which every object is cheap to allocate, use, and reclaim. In such an ideal system, every object goes away in a deterministic, orderly fashion the instant the programmer believes the object is no longer needed (regardless of whether cycles exist). Having invested countless hours into solving this problem, the .NET team believes that the only means of accomplishing this is by combining a tracing GC with reference counting. The benchmark data reflects that reference counting is too expensive to be used in a general-purpose way for all of the objects in programming environment. The code paths are longer, and the code and data working set is larger. If you then combine this already high price with the additional cost of implementing a tracing collector to reclaim cycles, you're spending an exorbitant price for memory management.
It should be noted that in the beginning days of .NET development, various techniques were researched to find a way to improve reference-counting performance. There have been reasonably high performance systems built on reference counting before. Alas, after surveying the literature, it was determined that such systems accomplished the improved performance by giving up some of their determinism.
As an aside, it might be worth noting that C++/COM programs don't suffer from this problem. Most high performance C++ programs that use COM use C++ classes internally where the programmer is required to explicitly manage the memory. C++ programmers generally use COM only to create the interfaces for their clients. This is a key characteristic that allows those programs to perform well. However, this is obviously not the goal of .NET, in which the issues of memory management are intended to be handled by the GC and not the programmer.