Earlier quoted context omitted.
Yes and no. LXR is a highly optimized deferred and coalesced reference counting (amongst many other optimizations) GC and it looks nothing like the RC implementations you see in other languages like Python, Nim, Swift, etc. So yes, reference counting can be performant, _but_ only if you are using a deferred and coalesced implementation as otherwise the simple implementation requires atomic operations for every pointe…
Rust doesn’t use multi threaded Rc unless you actually need to send it across threads.
The Garbage Collection Handbook, 2nd Edition
121–130 of 174 posts
Re: The Garbage Collection Handbook, 2nd Edition
#122Earlier quoted context omitted.
That is correct. Like Objective-C the compiler statically removes ARC when it can prove it doesn’t need it (or when you annotate it because where you’re getting it from is manually managing and giving you ownership of the reference). So within a function or cross function with LTO (although it looks like swift doesn’t yet have LTO [1] so I’m not sure about cross-module optimizations). > When receiving a return result…
> So within a function or cross function with LTO (although it looks like swift doesn’t yet have LTO [1] so I’m not sure about cross-module optimizations). I'm not sure Swift supports "static library modules" so in practice any linked object consists of a single module. > There actually is some elision that happens at runtime if you install an autoreleasepool if I recall correctly. There is a trick in the ObjC ABI th…
> but it's deterministic after compilation time so I wouldn't call it a runtime optimization.
What do you mean? My understanding is that autoreleasepool is 100% at runtime. The compiler is not involved afaik except to know to register autorelease with the currently installed pool.
Re: The Garbage Collection Handbook, 2nd Edition
#123Earlier quoted context omitted.
Because they don’t care as much about working set size as Apple does.
Sure, it is a tradeoff as basically every other technical choice. But we were talking about performance here, and especially in throughput, tracing GCs are much better.
The main advantage from a tracing GC is that you have an easier programming model (which isn’t a trivial trade off) but the downside is that you don’t have deterministic destruction which can make certain programming paradigms difficult (yes Java introduced alternate mechanisms to get you there if you care but it feels like a 100% bolt on rather than something integrated more neatly and elegantly and most developers don’t actually care).
Re: The Garbage Collection Handbook, 2nd Edition
#124Earlier quoted context omitted.
Tracing garbage collectors don’t generally win against reference counting connectors, especially when those reference counts are automatically elided via ARC (eg swift and objective C) or because they’re rarely used by means of composition (c++ and rust). Additionally, different kinds of application strategies are better depending on the use case (eg a pool allocator that you bulk drop at the end of some computation)…
Then why do every performant managed language opts for tracing GCs when they can? RC is used in lower level languages because it doesn’t require runtime support , and can be implemented as a library. As I wrote in another comment, even with elisions, you are still trading off constant writes on the working thread for parallel work, and you even have to pay for synchronization in parallel contexts.
Seriously. A single threaded reference counter is super cheap. Cross thread reference counts shouldn’t be used and I think are an anti pattern - it’s better to have the owning thread be responsible for maintaining the reference count and passing a borrow via IPC that the borrower has to hand back. There is also hybrid RC where you Arc across threads but use RC within the thread. This gives you the best of both worlds with minimal cost. Which model you prefer is probably a matter of taste.
CPUs are stupid fast at incrementing and decrementing a counter. Additionally most allocations should be done on the stack with a small amount done on the heap that is larger / needs to outlive the current scope. I’ve written all sorts of performance-critical programs (including games) and never once has shared_ptr in C++ (which is atomic) popped up in the profiler because the vast majority of allocations are on stack, value composition, or unique_ptr (ie no GC of any kind needed).
The fastest kind of GC is one where you don’t even need any (ie Box / unique_ptr). The second fastest is an integrated increment that’s likely in your CPU cache. I don’t think anyone can claim that pointer chasing is “fast” and certainly not faster than ARC. Again assuming you’re not being uncareful and throwing ARC around everywhere when it’s not needed in the first place. Value composition is much more powerful and leave RC / Arc when you have a more complicated object graph with shared ownership (and even then try to give ownership to the root uniquely or through RC and hand out references only to children and RC to peers).
Re: The Garbage Collection Handbook, 2nd Edition
#125Earlier quoted context omitted.
Sure, it is a tradeoff as basically every other technical choice. But we were talking about performance here, and especially in throughput, tracing GCs are much better.
Proof about throughput? Stating something as fact isn’t quite as strong as showing axes. Also performance has multiple axis for measuring: throughput, latency, memory usage, etc etc. Java eating all your memory and spending a non-trivial amount of overall CPU on a tracing collector which can negatively impact latency isn’t necessarily what people want efficiency wise where smearing that over total execution time tend…
Comparing naive RC to tracing GC is non-trivial. In order to have a fair comparison, you'd have to implement naive RC and tracing GC in the same system and then compare them across a set of benchmarks. I personally have never come across a great performance study which compared naive RC to tracing GC.
Re: The Garbage Collection Handbook, 2nd Edition
#126Earlier quoted context omitted.
Tracing garbage collectors don’t generally win against reference counting connectors, especially when those reference counts are automatically elided via ARC (eg swift and objective C) or because they’re rarely used by means of composition (c++ and rust). Additionally, different kinds of application strategies are better depending on the use case (eg a pool allocator that you bulk drop at the end of some computation)…
Swift and Objective-C ARC performance is quite poor.
Re: The Garbage Collection Handbook, 2nd Edition
#127Earlier quoted context omitted.
Swift’s value types have reference counts because they may have members that need their lifetimes to be managed appropriately. (For example, if they’re reference types.)
This is incorrect, value types are not referenced counted in Swift. If a value type contains a reference type member (usually an anti pattern!), then that member’s reference count is indeed incremented when the value type is copied. But it is not accurate to claim that value types themselves have reference counts.
Re: The Garbage Collection Handbook, 2nd Edition
#128Re: The Garbage Collection Handbook, 2nd Edition
#129Earlier quoted context omitted.
There was this project though. https://github.com/Roldak/AGC The best part is that it's faster than manual management. People will tell you they need do to malloc and free manually for performance, but when you actually run the numbers GC wins for a majority of use cases.
Tracing garbage collectors don’t generally win against reference counting connectors, especially when those reference counts are automatically elided via ARC (eg swift and objective C) or because they’re rarely used by means of composition (c++ and rust). Additionally, different kinds of application strategies are better depending on the use case (eg a pool allocator that you bulk drop at the end of some computation)…
Obviously though, this will be situation dependent.
Re: The Garbage Collection Handbook, 2nd Edition
#130Earlier quoted context omitted.
I don’t think they would, considering they’ve already finished their study.
You could have your own repo to counterpost every time someone like me refers to that old study with tainted results.