Ah you mean by causing cache stalls when doing increments/decrements after each assignment and allowing for cyclic references?
Ah you mean by causing cache stalls when doing increments/decrements after each assignment and allowing for cyclic references?
As for not allowing cycles, I consider that a feature. The headache of memory management doesn't go away with GC. You still have to avoid inadvertently keeping references to objects through the undo stack & so on. Unintentional strong refs creep through GC code just as easily as memory leaks creep through code with manual memory management. Almost universally, I find that GC'd projects large enough to have memory management best practices implicitly do away with this freedom at the first opportunity by calling for acyclic or single-parent object ownership graphs. These restrictions primarily make it easier to think about object lifecycle -- the fact that they allow refcounting to suffice for memory management is icing on the cake.
The Rust compiler does this. Even so, 19% of the binary size in rustc is adjusting reference counts.
I am not exaggerating this. One-fifth of the code in the binary is sitting there wasted adjusting reference counts. This is much of the reason we're moving to tracing garbage collection.
All of those optimizations that you're talking about (for example, packing reference counts into the class pointer) will make adjusting reference counts take even more code size.
> As for not allowing cycles, I consider that a feature. The headache of memory management doesn't go away with GC.
The fact that memory management is still an issue doesn't mean that we shouldn't make it work as well as we can.
In large software projects, cycles are a persistent issue. Gecko had to add a backup cycle collector over its reference counting framework, and observed memory usage decreased significantly once it was implemented.
Hopefully in future versions of PyPy an even better garbage collector. :-)
This means each increment/decrement is a virtual method call with the corresponding invocation costs.
This is why the .NET runtime caches the WinRT objects, and even re-uses them instead of making a 1:1 use like C++/CX does.
[1] https://developer.apple.com/library/mac/documentation/Genera...
.NET still does GC, it is only the WinRT APIs (something like COM) that manage resources through ref counting. There is some cool interop magic that makes this somewhat transparent to the programmer.
Apple's ARC is a compiler hack. It only works if you happen to use set of Cocoa libraries that are recognized by the compiler and allow for some magic incantation.
You cannot make any Objective-C library ARC aware.
ARC is a good solution for Objective-C, because Apple never managed to have their GC working safely in all situations, given the underlying C type system.
> .NET still does GC, it is only the WinRT APIs (something like COM) that manage resources through ref counting. There is some cool interop magic that makes this somewhat transparent to the programmer.
True, but C++ does not and you still have the performance penalty of reference counting.
The only way to have reference counting with good performance is do what Parasol or Objective-C do, by removing unnecessary increment/decrement operations thanks to dataflow analysis.
Which is something that you cannot do just by using the WinRT runtime and need to rely on the cleverness of the compilers.
Actually, are you aware that reference counting tends to be presented on the first chapter of many CS books about garbage collection as poor man's GC?
I don't understand. How does ARC rely on more than what NSObject provides? I'm coming from the C++ shared_ptr world and ARC does not feel much different so far (less explicit, but easier to optimise).
Just read this document.
https://developer.apple.com/library/mac/#releasenotes/Object...
You need to write code with lots of special cases to be able to have ARC active and not fall into strange compiler errors.
Most of the restrictions (bridge casts and naming methods) are interoperation with non-ARC code, and from working on Java/JNI I can assure you GC<>manual interaction was worse.
It is of course still quite possible to get abandoned memory through retain cycles.
Not very relevant. For UI code, responsive resource allocation and de-allocation is much more important than saving a few % CPU cycles.
> Actually, are you aware that reference counting tends to be presented on the first chapter of many CS books about garbage collection as poor man's GC?
Yes! Sometimes the conventional wisdom doesn't hold in the end, or it doesn't hold for all use cases. But I should have been more clear that ref counting is GC, whereas what I refer to as GC involves sweeping reference roots periodically to identify garbage.
> Not very relevant. For UI code, responsive resource allocation and de-allocation is much more important than saving a few % CPU cycles.
I beg to differ. I consider missile control radar systems of military applications a bit more important than UIs.
There are military applications using real time GC systems, which I can list here if you want.
I also have a German magazine here (Making Games Magazin 1/13) that explains how Witcher2 for the Xbox 360 makes use of a GC.
Anyway one thing I do agree, automatic memory management, regardless of the form, should be the any of any programming language.
Pure manual memory management should be treated like Assembly. It will never go away and should only be used for the very few cases where there is no other way around the problem at hand.
I should have mentioned that the primary reason WinRT seems to use reference counting is for interop reasons: its much easier to great a UI toolkit that is programmable in both C# and C++. Note that WPF never had a C++ interface, while WinRT has one without the need for any bridge code.
Reference counting has some interesting applications where it is more appropriate trace-based GC. Heck, sometimes we want old-fashioned arenas (Pascal!), it would be nice if our languages could give us some choices.
Manual memory management is annoying but sometimes necessary. I can see why native programmers don't want to give it up as it constitutes the primary performance difference these days between native and managed languages.