5 ms·
Correct me if I'm wrong, but: - GC pauses, Rc<T> does not, it's simply a deallocation by the last reference holder - Rc<T> still has predictable memory alloca
by marcus_cemes 5y ago
Correct me if I'm wrong, but:
- GC pauses, Rc<T> does not, it's simply a deallocation by the last reference holder
- Rc<T> still has predictable memory allocation/deallocation, GC is not guaranteed to run until needed
- More efficient memory use, no need to keep track of allocated objects
- The rest of the Rust language is a pleasure to use (imo)
- Python is slow for certain applications, and not concurrent
- Kotlin is kind of more niche than Rust, it's very popular in the Android community, like C# is popular on Windows
Just my 2 cents, I love progamming in all languages. There are some use-cases where a high level language is absolutely the way to go. For others, Rust provides much more control with a handy escape hatch. Absolutely don't go wrapping everything in Rc<T> like a madman, only when the reduced complexity is more beneficial than dealing with references/lifetimes.
- Quekid5 5y ago> GC pauses, Rc<T> does not, it's simply a deallocation by the last reference holder While the last bit is true, it may actually end up having to do lots of work. Think large object graphs where the last reference to any of it goes out of scope. Also, as a matter of terminology: Rc is a form of garbage collection. It's also a pretty bad general GC strategy at that -- which is why one doesn't just slap an Rc on everything.
- throwaway894345 5y ago> GC pauses, Rc<T> does not, it's simply a deallocation by the last reference holder There are pauseless GCs (e.g., Azul for JVM), and Go kicked off a trend of super-low-latency GC. Also, RC deallocation is O(N) while GC is usually O(1) (ignoring pedantry about how RC is a type of GC). Further, RC can't handle cycles automatically. > Rc<T> still has predictable memory allocation/deallocation, GC is not guaranteed to run until needed Deterministic GC exists, but admittedly isn't widespread. For most non-critical real time systems (e.g., video games) a low latency GC is probably sufficient. > More efficient memory use, no need to keep track of allocated objects I'm not sure if this is true? Presumably each RC has an int for its reference counter? I'm not sure what the bookkeeping overhead is for tracing GCs, but I'm guessing it's not O(N)? > The rest of the Rust language is a pleasure to use (imo) Agreed, but the borrow checker affects everything so this is a pretty small consolation in practice.
- heftig 5y ago> RC deallocation is O(N) What is N here? Number of allocations?
- throwaway894345 5y agoYes.
- ssokolow 5y ago> I'm not sure what the bookkeeping overhead is for tracing GCs, but I'm guessing it's not O(N)? I don't know about these days but, historically, the received wisdom was "Take the memory your algorithm should need and double it, to leave room for floating garbage and bookkeeping overhead. Otherwise, your performance will suffer as the GC is forced to run more frequently than is ideal." ("Floating garbage" being the jargon for stuff that's inaccessible but not yet collected.)
- quotemstr 5y agoNaive synchronous reference counting can lead to large pauses as well. What happens when you drop the last reference to the root of a 10,000-node search tree? You do 10,000 reference deferments and free()s. Reference counting might feel more incremental than GC, but really is not. There are tricks you can use, but you're better off with a fast, modern, pauseless real GC that comes with tons of other benefits. Look: modern GCs simply don't have pause time issues. The problem has been solved. We have concurrent marking and concurrent sweeping. Stop living in the 1990s!
- cesarb 5y ago> Naive synchronous reference counting can lead to large pauses as well. What happens when you drop the last reference to the root of a 10,000-node search tree? > You do 10,000 reference deferments and free()s. You do all that work at the precise point where the last reference was dropped. What people who complain about GC pauses dislike is the GC causing pauses in completely unrelated threads, including these threads that aren't even allocating or deallocating anything at that moment.
- deschutes 5y agoReference counting implies non deterministic frees. If you knew who the final owner of an object was, you wouldn't need reference counting. While it is true that many (most?) GCs have STW sections, it's not at all clear that it is a bad tradeoff.
- klabb3 5y ago> You do all that work at the precise point where the last reference was dropped. True, but rarely meaningful in practice. People don't anticipate spikes at implicit deallocation sites. On the contrary, they typically use RCs to share data without worrying about exact destructure time (i.e. same reason as GC), and thus will be caught off guard in either case. In fact so much so that even experts frequently introduce accidental RC cycles (causing hard-to-debug leaks). In the cases where you actually want destruction to be deterministic (e.g. large allocations, graceful teardown, kernel resources etc), neither a traditional GC nor RCs are a good solution. The simplicity and elegance of Rusts RAII scoped ownership model largely goes away with async, due to the unavoidable "Arc-hell".
- moonchild 5y ago> More efficient memory use, no need to keep track of allocated objects RC uses a traditional malloc/free-style heap, which requires bookkeeping for allocations. It also allocates an _additional_ word to track the reference count, which leads to poor cache behaviour (even in single-threaded programs, but especially in multi-threaded programs). Bumping/copying nursery incurs no bookkeeping overhead.