6 ms·
Rust has left the building
by cidd 3y ago
Rust has left the building
- rwmj 3y agoRust also uses reference counting, probably the worst sort of garbage collection.
- mr_00ff00 3y agoTracing is the worst in terms of performance
- SideQuark 3y agoThat depends. Deallocating a zillion little objects one a a time can be slower than doing them all in a batch.
- _a_a_a_ 3y ago[flagged]
- pjmlp 3y agoNot really, here it is winning hands down over Swift's ARC implementation. https://github.com/ixy-languages/ixy-languages https://github.com/ixy-languages/ixy-languages
- saagarjha 3y agoWasn't this the comparison that decided to use reference types for everything for no real reason?
- kaba0 3y agoI don’t know anything about the benchmark, but how would you test GC implementations without reference types?
- saagarjha 3y agoSwift’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.)
- danappelxx 3y agoThis 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.
- saagarjha 3y agoYes, fair enough. I was thinking of this more from the perspective of types that have internal reference types that are opaque so it’s effectively like the value type itself having a reference count on it, but yes, really it’s the internal storage that is getting the count.
- pjmlp 3y agoThe reason being comparing how various schemes of automatic reference memory management perform. Naturally if the purpose was to compare stack allocation performance other approach would have been taken.
- kaba0 3y agoAnyone claiming something like this obviously hasn’t dig into GCs. You honestly think that writing into memory at each access, especially atomically is anywhere near the performance of a GC that can do most of its work in parallel and just flip a bit to basically “having deleted” everything no longer accessible?
- mr_00ff00 3y agoa bit flip is not writing? Also do traces not have to work atomically? The program needs to stop, you can’t have it check roots as it runs. I’ll admit I am no GC researcher with ph.D experience, but your comment makes it seem you aren’t either.
- hayley-patton 3y agoTracing is batched up in GC pauses, rather than on every access as with naive RC. It is necessary to stop the world, but the work done in the pause does not need to use atomic operations. Atomics are handy in a parallel/multi-core tracing collector, but IME pointer chasing in tracing somehow manages to cover the time it takes to do atomic operations.
- sirwhinesalot 3y agoThe increment/decrement calls only occur on an explicit call to .clone(). No .clone(), no increment/decrement. You won't see many clones in rust code.
- rwmj 3y agoIt's how often reference counts are adjusted on hot paths that matters (including in libraries), and back to the original point, reference counting doesn't let you free groups of objects in one go (unlike a tracing GC). Also it'd be nice if the reference counts were stored separately from the objects. Storing them alongside the object being tracked is a classic mistake made by reference count implementations (it spreads the writes over a large number of cache lines). I was actually surprised that Rust doesn't get this right. Another issue with manual memory management is that you can't compact the heap.
- sirwhinesalot 3y agoThe amount of reference-counted pointers in most Rust code is a tiny fraction compared to boxes or compiler-tracked-lifetime references. Yes in theory it would be more efficient to store all the reference counts together, but that's in theory. In practice most Rust apps will not call clone on a shared pointer on a hot path and if they do it's usually 1 such pointer and they do something with the data as well (so it's all 1 cache line anyway) You can't compare Rust/C++ with Swift/Nim when it comes to RC, there just aren't enough reference count operations for it to matter much (unless you're in a shitty OO C++ codebase like me that pretends it is java with std::shared_ptr everywhere) Apps where heap compaction would be relevant in a low-level language like Rust or C++ will typically use a bump allocator which will trounce any kind of GC.
- nu11ptr 3y agoOnly when used in a naïve way, which Rust does not. For example, the increments/decrements are done only when "clone" is called and scope exit respectively, and based on Rust ownership/borrow checking, is rarely done combining the best of both worlds (but yes, implementations with aggressive increment/decrements in loops and on every function call can be very slow). Rust also separates Arc (atomic refs) and Rc (non-atomic refs) and enforces usage scenarios in the type checker giving you cheap Rc in single threaded scenarios. Reference counting when done in a smart way works pretty well, but you obviously have to be a little careful of cycles (which in my experience are pretty rare and fairly obvious when you have such a data type).
- ufo 3y agoThe book also has a chapter on reference counting ;-)
- medo-bear 3y ago[flagged]