Hmm... not in my experience at least, for instance Apple's ARC (which should be much better than "dumb" shared_ptr refcounting because the compiler does some static analysis and drops redundant retain/release operations) still can have a shockingly high runtime overhead and requires careful manual tweaking and general handholding to the point where the traditional manual memory management results in simpler code, at least in hot code paths.
Now GCs may well be worse, but performance-wise they really can't be much worse than ARC. ARC may sometimes prevent unpredictable GC spikes, but only by spreading out the same (or worse) cost along the timeline (which is at least something, but many GCs simply haven't been designed for the "prevent spikes" requirement).
There simply is no silver bullet for dynamic memory management, at least if both memory usage and performance matters.
The problem with rc is not memory access but synchronization.
RC speed is not even close to the reason Python doesn't have proper multithreading.
(The GIL, and API/ABI guarantees to third party C-based extensions making it difficult to remove it, is more like it. The GIL was added to aid in RC atomicity - but it's not the speed of RC that's the issue).
Actually, I've heard that Go sacrificed speed big time to minimise its pauses. Garbage collectors generally face a latency/throughput tradeoff, and I believe Go is no exception.
That said, fast GC with reasonable pauses existed long before Go. I personally know of OCaml and its generational, incremental GC. I expect Go built on that knowledge to find its own sweet spot.
If you want more information about this topic, there is a nice talk by Larry Hastings: https://www.youtube.com/watch?v=pLqv11ScGsQ
So it's hard to make alternative implementations that don't die.
https://github.com/ixy-languages/ixy-languages
https://forums.swift.org/t/swift-performance/28776
It is no wonder that Swift 5.5 brings aggressive compiler optimisations that can even break code that naively relies on basic ARC behaviour.
RC also has pauses, pretty lengthy ones with cascade deletions, and can even lead to stack overflows.
"CppCon 2016: Herb Sutter “Leak-Freedom in C++... By Default""
Which is why as GC algorithm reference counting is only for toy implementations.
Any reference counting implementation that cares about performance in multicore environments is almost indistinguishable from a tracing GC implementation.
In fact, C++/WinRT, uses background threads to diminish the performance impact of calling destructor and cascading deletions.
https://devblogs.microsoft.com/oldnewthing/20191018-00/?p=10...
But you can find on net whatever you seek, whatever you are looking for.
> Which is why as GC algorithm reference counting is only for toy implementations.
That's what I heard from last decade. And then experience has outgrown likes or dislikes.
The fact that Swift and Objective-C get outperformed in any research about automatic memory management is quite real, not urban myths.
What experiences would be that? "GC pauses" exist in stop-the-world garbage collector's phase. If you need a concurrent one - they exist just as well.
That languages get popular is no surprise. But what was a little bit surprising for me was that the tech the language uses gets spread and popular all over -- outside of that language as long as that language stays popular.
I right now am think automatic reference counting is the way to go. In a sense C++ RAII is also ARC. But a compiler level support is better.
"Garbage collecting", so, you mean, you're leaving garbage around then? Why?
With RC you're acting on the deallocation as soon as you are allowed to. Sure, you don't need to actually deallocate at that time, but you're acting upon it.
"Oh but what about loops" well, you can work around those (and they are rare).
My point is not that GCs are not useful. My point is that there is a better way of dealing with allocations if you know your object is not used anymore and not just treating memory as infinite.
And despite what some people think, malloc/free are not O(1) free lunch.
If you want to talk determinism, you need to actually invest into deterministic behaviour - something that either requires dropping dynamic memory allocation altogether, or tends to go for GC with known determinism guarantees (for example, IBM Metronome).
> And despite what some people think, malloc/free are not O(1) free lunch
Of course. Be it through a GC allocator or not. If you're at the point where the allocator is giving you trouble then GC/RC is the least of your problems ;)
It was reference counting in the 80s and 90s. And then tracing GC people stepped in. "Reference counting is worse of both worlds. It's slower than GC because all these memory have to be touched!"
But real life experience continues to show ref counting doing better. And GC users pre allocating object pool to avoid GC pauses. Proponents still in denial. "What if a large object is deleted? That will also create GC pause like delay."
And now here we stand. Back to reference counting.