4 ms·
If the runtime mechanically detects that an object will never be used again, without you having to explicitly say so (and woe unto you if you're mistaken), that
by prodigal_erik 10y ago
If the runtime mechanically detects that an object will never be used again, without you having to explicitly say so (and woe unto you if you're mistaken), that's what's meant by garbage collection. Reference counting does have a deterministic cost, but it's extremely high and applies to everything you do. Copying collection benefits from deferring and batching the work when most objects die quickly and can be ignored with zero effort (just recycle the arena containing all of them).
- WildUtah 10y agoYou can write a reference counter in three short lines of code that works the same as shared_ptr<T> or Swift. A modern automatic garbage collector requires a threading library plus tens of thousands of lines of intricate code. We're not comparing like with like here.
- prodigal_erik 10y agoThe three line version is really easy to write. And every time you assign to a pointer, it requires uncached atomic updates to the refcounts of the old and new objects, which is staggeringly expensive compared to a block of code that can go unused for minutes at a time. And all it gets you is learning that a small piece of memory is available slightly sooner, but you'll probably want to coalesce your free memory anyway for better locality.
- WildUtah 10y agoI hope that the 100-man years of top engineers version has some benefits over the 3-line newbie approach.
- lokedhs 10y agoPeople tend to think that refcounting must be faster than a tracing GC because you don't have to scan the memory. The second half of the previous sentence is true, but what they forget is that refcounting needs to do a lot of things that a GC doesn't have to: Like you said, need to update the reference every time it's moved. malloc becomes much slower, compared to a GC language (with a compacting GC) where malloc is effectively just a single add instruction. free also needs to do a lot of bookkeeping while the GC language doesn't need to do anything. Multithreading introduces another set of issues when dealing with refcounting that is not a problem with a GC.
- je42 10y agoMultithreading also introduces issues for GC. It needs to stop all threads. If you look at how much work has been delivered towards the GC's of for example JVM, Go and V8. It is a really tough problem to get right for all application types. Reference counting is very predictable. And if you see a bottle neck you can start fixing it. And with ARC (Swift/ObjC) you get even compiler support to optimize all ref counting administration. Further malloc doesn't have anything to do with ref counting as ref counting sits on top if it. Further, GC languages also need to do book keeping: Generations and Compaction.
- lokedhs 10y agoThat is true, but only during GC itself. Refcounting causes these issues every time the reference is copied. For malloc, the benefit with a compacting GC is that the free memory will always be in a contiguous segment. Therefore, a malloc operating is similar to a stack allocation in that all you need to do is to move a single pointer. Without a compacting GC, you need to search a tree whenever you want to allocate memory.
- wahern 10y agoIn order to know whether an arena is empty, you need to have walked, at a minimum, each object that was in the arena. That applies for copying collections too as during the copy phase you've walked and inspected each object that might be copied into the arena at least once. Arenas do not reduce the cost of garbage collection to O(1). And in any event arenas are not solely the preserve of sweeping or sweeping+copying collectors. The algorithmic complexity of a sweeping collector is identical to that of a reference counting collector that can also break cycles. See A Unified Theory of Garbage Collection at http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.146.3973 http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.146.... A reference counting collector that _cannot_ break cycles (like in Swift) might have lower algorithmic complexity. I'm not sure. The biggest bone of contention with reference counting is the constant adjustment of the reference count of objects on the stack. OTOH, the bone of contention with sweeping collectors is constantly walking all extant objects, including ones not directly on the stack. There are various optimizations you can make to one or the other or both; many arguments about how real-world scenarios tax one or the other model; and many arguments about which is easier to optimize. But at the end of the day reference counting is no worse in terms of algorithmic complexity than sweeping. What matters most will be the quality of implementation. Is the compiler smart enough to know that an object passed 3 routines deep doesn't really escape the stack scope? If it can do that, it can elide all the cost of either approach.
- WildUtah 10y agoWhat matters most will be the quality of implementation. Is the compiler smart enough to know that an object passed 3 routines deep doesn't really escape the stack scope? If it can do that, it can elide all the cost of either approach. This is the plan with Swift and what makes it zippy. bone of contention with sweeping collectors is constantly walking The real problem is that you cannot determine when the program will pause. It makes interactive and soft realtime impossible with gc. (Hard realtime should not run a generic allocator at all.) You can't write anything but servers and unpleasantly unresponsive apps. Android developers have to carefully jump through hoops to avoid allocating any RAM at all if they don't want to bug their users. For years when the chips were slow, ref counting was a major competitive advantage for iPhone. A hundred-billion dollar win. And then there's system software. You can't afford a live, unpredictable runtime messing with you in systems code so anything that touches low level code can't use gc. There's a disincentive to really invest in a language that simply can't ever do a full stack, even if you're unlikely to need to write a device driver anytime soon. That's why no major browsers, performant ACID databases, or fast app servers depend on RAM gc.