Why no Reference Counting + Garbage Collection in C#?
I come from a C++ background and I've been working with C# for about a year. Like many others I'm flummoxed as to why deterministic resource management is not built-in to the language. Instead of deterministic destructors we have the dispose pattern. People start to wonder whether spreading the IDisposable cancer through their code is worth the effort.
In my C++-biased brain it seems like using reference-counted smart pointers with deterministic destructors is a major step up from a garbage collector that requires you to implement IDisposable and call dispose to clean up your non-memory resources. Admittedly, I'm not very smart... so I'm asking this purely from a desire to better understand why things are the way they are.
What if C# were modified such that:
Objects are reference counted. When an object's reference count goes to zero, a resource cleanup method is called deterministically on the object, then the object is marked for garbage collection. Garbage collection occurs at some non-deterministic time in the future at which point memory is reclaimed. In this scenario you don't have to implement IDisposable or remember to call Dispose. You just implement the resource cleanup function if you have non-memory resources to release.
EDIT: From the comments so far, this is a bad idea because
I think number one is valid, but number two is easy to deal with using weak references.
So does the speed optimization outweigh the cons that you:
If your resource cleanup mechanism is deterministic and built-in to the language you can eliminate those possibilities.
Brad Abrams posted an e-mail from Brian Harry written during development of the .Net framework. It details many of the reasons reference counting was not used, even when one of the early priorities was to keep semantic equivalence with VB6, which uses reference counting. It looks into possibilities such as having some types ref counted and not others ( IRefCounted
!), or having specific instances ref counted, and why none of these solutions were deemed acceptable.
Because [the issue of resource management and deterministic finalization] is such a sensitive topic I am going to try to be as precise and complete in my explanation as I can. I apologize for the length of the mail. The first 90% of this mail is trying to convince you that the problem really is hard. In that last part, I'll talk about things we are trying to do but you need the first part to understand why we are looking at these options.
...
We initially started with the assumption that the solution would take the form of automatic ref counting (so the programmer couldn't forget) plus some other stuff to detect and handle cycles automatically. ...we ultimately concluded that this was not going to work in the general case.
...
In summary:
The garbage collector does not require you to write a Dispose method for every class/type that you define. You only define one when you need to explicitly do something to cleanup ; when you have explicitly allocated native resources. Most of the time, the GC just reclaims memory even if you only do something like new() up an object.
The GC does reference counting - however it does it in a different way by finding which objects are 'reachable' ( Ref Count > 0
) every time it does a collection ... it just doesn't do it in a integer counter way. . Unreachable objects are collected ( Ref Count = 0
). This way the runtime doesn't have to do housekeeping/updating tables everytime an object is assigned or released... should be faster.
The only major difference between C++ (deterministic) and C# (non-deterministic) is when the object would be cleaned up. You can't predict the exact moment an object would be collected in C#.
Umpteenth plug: I'd recommend reading Jeffrey Richter's standup chapter on the GC in CLR via C# in case you're really interested in how the GC works.
Reference counting was tried in C#. I believe, the folks that released Rotor (a reference implementation of CLR for which the source was made available) did reference counting-based GC just to see how it would compare to the generational one. The result was surprising -- the "stock" GC was so much faster, it was not even funny. I don't remember exactly where I heard this, I think it was one of the Hanselmuntes podcasts. If you want to see C++ get basically crushed in performance comparison with C# -- google Raymond Chen's chinese dictionary app. He did a C++ version, and then Rico Mariani did a C# one. I think it took Raymond 6 iterations to finally beat the C# version, but by that time he had to drop all the nice object orientednes of C++, and get down to the win32 API level. The entire thing turned into a performance hack. C# program, at the same time, was optimized only once, and in the end still looked like a decent OO project
链接地址: http://www.djcxy.com/p/54528.html上一篇: 我如何说服我的同事不要在任何事情上实施IDisposable?
下一篇: 为什么没有引用计数+垃圾收集在C#中?