4 ms·
Isn’t one of the benefits of RC better (lower and more predictable) latency than with GC? Basically, you can presict when (and how much) garbage will be collect
by tomp 7y ago
Isn’t one of the benefits of RC better (lower and more predictable) latency than with GC? Basically, you can presict when (and how much) garbage will be collected, and if it turns out that’s too much, you can fix your code... good luck doingthat with GC.
The downside is, of course, that it requires much more care (to avoid cycles)
- pjmlp 7y agoOn single core without threading. If you add multi-threading and multi-core, there is lock contention for every single memory access to update the related counter. Additionally, if there is a big data structure in use, reaching zero will trigger a cascade deletion events reaching stop-the-world like effect. Which, depending on how the deletion was implemented, might trigger a stack overflow in very deep structures. Herb Sutter has a very interesting talk about the bad issues of reference counting and how to work around them. CppCon 2016: Herb Sutter “Leak-Freedom in C++... By Default.” https://www.youtube.com/watch?v=JfmTagWcqoE https://www.youtube.com/watch?v=JfmTagWcqoE There are multiple ways to optimize reference counting, like deferred counting, cycle collectors and a couple of others, which when you are done with all them, ends up being quite similar to having a tracing GC anyway.
- zozbot234 7y ago> If you add multi-threading and multi-core, there is lock contention for every single memory access to update the related counter. You only have to update the counter when creating (or destroying) new "owning" references that might outlive any other reference to the object. This is a rare operation, and doing it potentially from multiple threads in a way that requires atomic update is even rarer. > Additionally, if there is a big data structure in use, reaching zero will trigger a cascade deletion events reaching stop-the-world like effect. This is a side effect of deterministic disposal, of course. And it only happens when freeing up large object subgraphs, not just any and all "large data structures". Yes, C++ implements reference counting in a non-ideal way. Swift is also quite bad. But one can do better.
- pjmlp 7y agoWhen one does better it usually ends up with some form of tracing GC implementation, as per most CS research papers, it just gets to call it reference counting with optimizations to feel better.
- zozbot234 7y agoThat's definitely true of some enhanced variations on reference counting. The changes I mentioned though do not involve any tracing of live data at runtime. (Although once one introduces the possibility of general cycles, it seems hard to avoid the requirement of tracing some live data.)
- cesarb 7y ago> Additionally, if there is a big data structure in use, reaching zero will trigger a cascade deletion events reaching stop-the-world like effect. Even a deletion cascade won't stop the world: only the single thread which reached zero will be "stopped". While in tracing GC, a "stop-the-world" stops all threads, even the ones which aren't doing any allocation or deallocation at the moment.
- zozbot234 7y agoThere are concurrent GC's that don't pause all threads while running garbage collection. Plus the whole point of GC is that it's what you use when you just don't know at runtime which operations should involve "allocation or deallocation" of objects. From the POV of tracing GC, any "new" reference to an object might be the reference that extends its lifetime and prevents it being collected, and conversely when removing a reference.
- imtringued 7y agoThose GCs are special exceptions. Most modern GCs just aim to have bearably low pause times.
- pjmlp 7y agoHigh performance tracing GC algorithms don't stop all threads. Also there are tracing GC that operate with local heaps.
- fulafel 7y agoPeople routinely profile and optimize the amount of memory churn in GC languages, and many non-RC GCs provide good telemetry about it. In RC systems you don't escape latency spikes from cascading deallocations and nondeterministic malloc/free call latencies. The malloc impl underlying RC still needs to occasionally work quite a lot to recycle freed memory, just with additional constraints compared to non-RC GCs.