C Sharp

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.

The (Almost) Perfect Solution

So, like most things in life, you can't have it all with regards to the resource management solution. But what if you could have deterministic finalization on just those objects that you need it on? The .NET team spent a lot of time thinking about this. Remember that this was in the context of exactly duplicating Visual Basic 6 semantics within the new system. Most of that analysis still applies, but some ideas that were discarded a long time ago now look more palatable as resource management techniques rather than transparent Visual Basic 6 lifetime semantics.

The first attempt was to simply mark a class as requiring deterministic finalization either with an attribute or by inheriting from a "special" class. This would cause the object to be reference counted. Many different designs were investigated that included both subclasses of System.Object and changing the root of the class hierarchy to some other class that would bind the reference-counting world to the non-reference-counting world. Unfortunately, there were a number of issues that could not be circumvented, as described in the following sections.