Garbage Collection vs. malloc/free
groups.google.com
groups.google.com
Current-generation garbage collectors have far better performance, and many research GCs support concurrent, pause-free collection.
(And that leaves aside the non-performance benefits of a GC, in terms of engineering simplicity and bug elimination.)
Does require custom hardware or kernel cooperation for speed (e.g. it needs to do batched MMU operations without clearing the TBL on each 2MB page). Looks like it's got a better read barrier than the Pauseless one; that does of course cost extra on stock hardware.
And so the perpetual argument goes: GC is superior to manual memory management (the latter of which is "adding needless effort to writing software"), and the performance is just as good, and the cases where performance is not just as good will be fixed Real Soon Now.
In GC enabled systems programming languages like the Oberon family, Modula-3, D, Sing#, one has finer control over the types of available memory.
- The usual GC allocated memory with the usual set of possible GC implementations
- Stack objects
- Global objects statically allocated
- Manual memory management inside unsafe blocks via untraced GC references
Not all GCs are made alike.
I have seen problems with stalling caused by kernel memory heap defragging on linux resulting in some serious thrashing. What that means is that the issue of heap fragmentation can be a problem regardless of which language used.
Better to avoid heap fragmentation to such extents by applying a better allocation strategy imo.
I'm not really convinced. How well does it stack up when the competition is a copying generational collector?
Interoperability with FFIs is one of the advantages of reference counting over GC. You don't have to worry about pinning allocations, allocation coloring, unscanned roots, etc. The ObjC refcounting operations (CFRetain/CFRelease), and the collection types (CFArray, CFString, CFSet...) are all trivially available from C as well.
I speculate that this better interoperability with C is why Apple deprecated GC and went with ARC. We can see Microsoft sort of moving in the same direction with WinRT.
(As an aside, there was an optional GCed variant of objective-c around for a while. Not sure what the performance impact was vs ref counted.)
It's worth noting that Apple has implemented GC in Objective-C on OS X before, but deprecated that in favour of its ARC implementation -- probably because its garbage collection implementation was no good at all (performance-wise).
By the time ARC was announced, there were still lots of corner cases in the ways code compiled with GC was interacting with code that wasn't compiled with GC enabled.
Plus, if you check Apple's developers documentation from those days, great care was required to make sure the GC could play nice with the C part of Objective-C.
So, in reality the ARC approach was taken, because it was the only way to have a working automated memory management, compatible with Objective-C code overall. Of course, being Apple, they sold it as a better solution for memory management and not as a result from their failure to implement a sound GC for Objective-C.
Both construction and destruction will allocate or can release memory, respectively, which I would think would bottleneck before any atomics or memory barriers inside shared_ptr. To me, the first likely port of call for improving performance in these cases is therefore a custom memory allocation strategy like a memory pool.
Copying can be a concern, but most containers and standard algorithms should be move aware now. You should be moving shared_ptr's far more often than you copy them.
All that aside, thread-safe by default seems to be the sane decision in this era.
A simple copying or mark-and-sweep collector is far easier to write than even basic dataflow-analysis optimizations. Implementor effort is hardly an argument against garbage collection; implementing efficient garbage collection is no worse than implementing a good optimizer or efficient code generation.
"Basic c++ shared pointers take up pretty much 90+% of what people need in GC"
They do so in a way that is right in the programmers face, adding needless effort to writing software, and can actually wind up being slower than a modern garbage collector. Shared pointers are a mistake, not quite as bad as auto_ptr but pretty bad nonetheless; the committee should have just introduced a garbage-collected smart pointer class and kept things simple (I guess that would not be the C++ way, though).
Garbage collection limits your object model, but Java's is much more limited than required for garbage collection. For example, in C++, you might pass small structs on the stack or in registers, while in Java you pass a pointer to a heap allocated object. But there is no reason a garbage collector can't handle value objects allocated on the stack, and indeed the CLR supports that feature.
All a garbage collector prevents you from doing is hiding pointers in integers and the like. But that's not as significant a limitation as not being able to say flat arrays of structs, something that is totally compatible with garbage collection.
And C++'s hideous shared_ptr system isn't a good thing to point to.
Single ownership with weak references is effectively what you have in C, though I guess compiler support for distinguishing which references are weak or strong is nice.
For refcounting and real-time, just let me leak the cycles. The non-realtime part of reference counting is the cycle detection, let me control the cycle sweeps and everybody's happy.
Maybe you are happy, but 99.9% of people would probably be very unhappy with that solution. How would you even go about accomplishing that in a way that wouldn't make you lose your mind? I can only imagine the complexity of having to decide how many cycle sweeps need to be done every time I reduce the reference count on an object/struct. I also think the runtime performance of enforcing that kind of limit would out way any possible benefit.
Consider a soft real-time environment like a game. Under RC, the time required to render a single frame depends only on the work done in that frame. Get it to 16 ms and you're done. But under GC, deallocation work can accumulate. A frame that would otherwise render in 16 ms may take much longer, due to the laziness of previous frames. That makes it harder to optimize, and indeed you'll often see advice like "frames must do zero GC allocations." Yikes!
Things may be different in hard real-time systems, which I know use specialized allocation schemes optimized for worst-case latency instead of bandwidth.
[1]Google has pdf. BTW, how do i extract a long living pdf link from a google link ?
Otherwise, several/most of the JVM's GCs do a very good job of handling this for you. Objects that were allocated consecutively by the same thread will tend to be kept close together in memory.
I guess the debate really isn't an A vs B thing. It's just a spectrum and deciding which side of the spectrum you want to start on.
This is hardly the case, especially on modern multi-core hardware. Writing a GC that works well in a concurrent environment is a huge undertaking. And unless your system is very simple, you'll often be better off with a good general-purpose GC.
A shared_ptr introduces a lot of contention.
A simple GC (or resettable arena allocator) can make use of this knowledge, and be quite a bit faster in those specific cases.
It's hard to beat the man years of work in generic GC that works in all cases, but it's not that hard to beat it in specific situations when the application author knows the details of how the application will do the allocations.
99% of the time, writing your own custom allocation strategies is a waste of time. Sometimes, though, it can be a win, allowing you to allocate and free in a matter of tens of CPU cycles with no GC pauses at all.
Agreed, but again, if you're willing to put that effort in you can do it in a GCed language.
Wait, how can you turn off GC'd managed memory in Java, and do it yourself? I didn't know you could do that in Java?
BUT what that means is that you have create your own custom implementations of the data structures you need and you'll have to write your own memory allocator.
Unless that memory area holds just a simple data BLOB (like a video file) you're always going to be much more productive implementing the entire thing in C++.
Or use a GC enabled systems programming language, that provides control over what is allocated via GC or via other means.
This is the only voice of reason in this thread full of bullshit by monkeys who have obviously never used C to any extent.
But hey.
Some of us are even older than C, and are thus aware that there used to be a time and age where C only mattered for UNIX developers.