8 ms·
Ridiculous. The problem is not that you don't know when/where the lifetime will end — that can usually be characterized by a terse "English" description. The p
by norswap 7y ago
Ridiculous.
The problem is not that you don't know when/where the lifetime will end — that can usually be characterized by a terse "English" description. The problem is that this lifetime is dynamic in nature.
The end of the lifetime of an object may coincide with some user input, for instance.
At this point, either you go back to manual management, with the potential for errors (and for what it's worth, I think manual management is fine in many cases) ... or .... or what, exactly?
Even Rust doesn't solve that problem at all. If your objects can survive outside of a "linear" execution, which is the case in interactive or multi-threaded programs, you're falling back on reference counting — garbage collection.
No one has ever devised a scheme that lets you specify very dynamic lifetimes AND statically checks that no leak can occur.
I'd stake a lot on that being impossible in general, and the best we can hope for being an AI that searches a way to insert the manual memory management calls (mostly, "free" and a minimal set of reference counts) assorted with a proof that this change will not cause any leaks or invalid accesses. We're a long way off that yet.
- simias 7y agoI don't see your point. Of course sometimes the lifetime of an object is not tied to code scope but actually to something dynamic. Let's say for instance when you close a tab in your browser you expect the resources to be freed (ignoring caching to simplify the argument). Clearly somewhere in your code you have to explicitly handle tab closing and break the references to allow the GC to do its job. Why not free the resources here while you're at it? When you say "manual memory management" if you're thinking C-style malloc-free then you have a point, it's very easy to forget a free() somewhere. But any language with destructors can handle these situations without much more overhead than GC-based approaches. Just remove your object from whatever data structure was holding it and let the language automagically run the destructor for you. I find RAII a lot easier to model and think about than "you drop this reference and one day maybe your object is destroyed, but don't really rely on that". >No one has ever devised a scheme that lets you specify very dynamic lifetimes AND statically checks that no leak can occur. GC doesn't solve that either. If you're not careful and let a reference to old data dangle somewhere in your code you can effectively "leak" data just fine. When there's no clear ownership and nobody knows who's supposed to clean what it's very easy to end up with data dangling everywhere through complex ownership graphs. GC may mitigate some use-after-free problems (generally by masking the problem) but that is something that can be solved without GC either. I'm not saying that applications with (justifiably) extremely complicated ownership semantics that also require very high performance don't potentially benefit from using a GC and that it could outperform manual memory management by, for instance, batching the object deletions. What I'm saying is that it's that such applications are few and far in-between, basically 100% of all the code I've ever wrote in my ~15years as a professional software developer didn't have such requirements. GCs should be an opt-in niche tool used to solve specific problems, not a kludge to let developers write sloppy code and get away with it.
- lossolo 7y ago> Clearly somewhere in your code you have to explicitly handle tab closing and break the references to allow the GC to do its job. Why not free the resources here while you're at it? You are missing the point. The main point behind GC is removing the complexity of writing the software. Writing your own destructors, thinking about when to free your memory or writing lifetime annotations, needing to design your app in specific way to satisfy the borrow checker etc in languages like Ada/C/C++/Rust all are additional complexity and mental overhead that is removed by GC. Your point about "just do this X and you don't need to use GC" is a reason people use GC languages, because they don't want to think about or write this "X".
- irq11 7y agoHaving spent years writing code in both GC’ed and non-GC’ed languages, it’s pretty clear that it programmers spend about the same amount of time worrying about memory management with either paradigm. The main differences are that people using GC systems spend their time doing magical incantations to manage the GC wizard, and they’re a lot more smug about the goodness of their system.
- cblades 7y ago>programmers spend about the same amount of time worrying about memory management with either paradigm I have no idea how you've come to that conclusion. For the vast majority of memory allocation in any GC'd language I can think of, you spend zero time thinking about memory management 98% of the time. whereas in a manual language, you must consider it every time you allocate memory. That's not a bad thing, it's often dead simple in the vast majority of contexts, but still. I've also very rarely seen code in professional code that's mean to poke or prod the GC into running.
- dleslie 7y agoFor 95% of the code you write it's not a concern; that last 5% sure can eat up time if your software has any concern about performance.
- dleslie 7y agoIf the lifetime can be expressed with a state machine then it needn't be garbage collected so long as the language is sufficiently expressive. Reference counting isn't garbage collection, as most people consider it. There is no need to sweep or otherwise traverse memory to discover objects that are not referenced. Claiming that ref counting is gc is a bit like claiming malloc/free is gc.
- norswap 7y agoI've always seen automatic reference counting classified as GC. e.g. https://users.cecs.anu.edu.au/~steveb/pubs/papers/rc-ismm-2012.pdf https://users.cecs.anu.edu.au/~steveb/pubs/papers/rc-ismm-20... > Reference counting and tracing are the two fundamental approaches that have underpinned garbage collection since 1960. https://www.cs.virginia.edu/~cs415/reading/bacon-garbage.pdf https://www.cs.virginia.edu/~cs415/reading/bacon-garbage.pdf > Tracing and reference counting are uniformly viewed as being fundamentally different approaches to garbage collection that possess very distinct performance properties. This last one is great if you want to understand GC tradeoffs btw, highly recommend it. --- And as the first paper implies, refcounting is often slower (because it trashes caches). The issue is having to propagate the diminution of refcounts amongst a graph of references. This also creates de facto "pauses", much like tracing GC (although arguably more predictable!). And this "propagation of diminished refcount" is very much a memory traversal — (probably) smaller in scope than (non-incremental) tracing, but also much less local.
- dleslie 7y agoInteresting! I'll be reading that today.
- nickpsecurity 7y ago"If the lifetime can be expressed with a state machine then it needn't be garbage collected so long as the language is sufficiently expressive." One programmer here told me he does that in Ada and/or SPARK Ada using enumerated types encoding states. Now there's two of you. Most stuff I see like this are linear/affine/dependent types or separation logic. I rarely see people talking about simple solutions like this. Do you have any links that go in-depth on it with examples? It would be good to have something to pass along to people interested in this.
- crimsonalucard 7y agoAny lifetime that depends on an io loop or user input cannot be determined within the loop Period. Even if you have an asic designed for garbage collection. It cannot even be dynamic. Basically in these cases you have to extend the lifetime to beyond the point of indeterminism into the point of determinism or in other words move the life time outside of the loop. Worst case scenario you move the lifetime to right before termination of the program.