News for hackers. Stuff that matters.
Re:Garbage Collection by munificent on Saturday November 30, 2019 @05:24PM (#21672483)
> They almost "just work", except for circular references

Well, and they're often slower since they require mutating the reference count on every single time a field is stored. You can optimize that using lazy reference counting, or not updating refcounts for references on the stack and instead scanning the stack before a collection. But at that point... you're halfway to implementing a tracing collector.

Every refcounting implementation eventually gets "optimized" to the point that it has most of a tracing collector hiding inside of it. I think it's simpler, cleaner, and faster to just start with tracing in the first place.

There's a reason almost no widely used language implementation relies on ref-counting. CPython is the only real exception and they would switch to tracing if they could. They can't because they exposed deterministic finalization to the user which means now their GC strategy is a language "feature" that they're stuck with.

That being said, ref-counting is fine for other kinds of resource management where resources are pretty coarse-grained and don't have cyclic references. For example, I think Delphi uses ref-counting to manage strings, which makes a lot of sense. Many games use ref-counting for tracking resources loaded from disc, and that also works well. In both of those cases, there's nothing to trace through, and the overhead of updating refcounts is fairly low.

Re:Garbage Collection by nostrademons on Saturday November 30, 2019 @07:50PM (#21673065)
There's a classic paper that shows that refcounting and GC are in fact duals of each other, where GC is effectively tracing live objects and refcounting is tracing dead objects:

https://dl.acm.org/citation.cfm?id=1028982

This had a number of important corollaries to this. One is that they have opposite performance characteristics: GCs make creating new references fast but then create a large pause when RAM is exhausted and a collection happens, while refcounts make creating new references slow and create a large pause when large object graphs are freed all at once. Another is that nearly all high-performance memory management systems are hybrids of the two: lazy refcounting is basically like implementing a local garbage collector and then feeding the live set of that into the refcounts, while generational garbage collection is like implementing a local refcount (the write barrier) and feeding the results of that into the root set.

Re:Garbage Collection by blattimwind on Saturday November 30, 2019 @07:25PM (#21672964)
> There's a reason almost no widely used language implementation relies on ref-counting. CPython is the only real exception and they would switch to tracing if they could. They can't because they exposed deterministic finalization to the user which means now their GC strategy is a language "feature" that they're stuck with.

Reference counting and address-semantics (which prohibits moving objects, so even if you work around the refcount, you can only do a tracing GC, but you don't get to compact) are deeply ingrained into CPython's C API as well, which is very widely used.

Re:Garbage Collection by smueller1234 on Sunday December 01, 2019 @07:51AM (#21675234)
For what it's worth, Perl (5) has the same problem as CPython. Accordingly, there's not only heaps of allocation- and ref-counting-avoidance optimizations (eg. the stack isn't recounted) but also heaps of bugs from the optimizations. Again, the (main) stack not owning references is the biggest source of these bugs.

The problem with predictable destruction, we typically called "timely destruction", but more accurate would've been "immediate destruction" and if your language guarantees it, it tends to be great for automatically releasing resources (memory, file handles,...) in a lexically predictable manner. Softening any such guarantee should lead to entertaining resource races magically appearing in the real world. It occurs to me now that I never checked what pypy guarantees if anything?

We (Perl) never really came up with a great strategy for working around this (you tended to get the worst of both worlds in most naive reimplementations of the behavior in a GC-based interpreter) and while I certainly haven't tried to work out a clean argument to the effect, I'm fairly convinced it won't fly at all.

Re:Garbage Collection by lizmat on Sunday December 01, 2019 @08:02AM (#21675267)
Raku (née Perl 6) has phasers that will be called when exiting a scope. One such idiom is:

    {
        # do stuff
        my $dbh = DB.connect(...);
        # do stuff
        LEAVE .disconnect with $dbh;
        # do stuff
    }
Whenever the scope is left (this could be because of an execution error, or a `return`), the code of the LEAVE phaser will be executed. The `with $dbh` checks whether the $dbh variable contains an instantiated object. If so, it topicalizes (set $_ to it) and calls the disconnect method (`.disconnect` being short for `$_.disconnect`).

For more complex uses, and more tuneable finalizing, there is the `FINALIZER` module in the ecosystem: https://modules.raku.org/dist/FINALIZER

Re:Garbage Collection by smueller1234 on Sunday December 01, 2019 @08:49AM (#21675463)
Sure, but "schedule action at scope exit" is an easy (assuming your runtime already knows how to unwind the stacks) problem to solve. "Perform escape analysis and guarantee immediate destruction; efficiently without full gc nor refcounting" is not and they're not the same problem at all.
Re:Garbage Collection by tyingq on Sunday December 01, 2019 @07:45AM (#21675218)
"There's a reason almost no widely used language implementation relies on ref-counting. CPython is the only real exception"

Perl is also ref counted. Swift too.

Edit: Also TCL, and PHP is mostly recounted...the "GC" just deals with circular refs.

Re:Garbage Collection by lizmat on Sunday December 01, 2019 @07:53AM (#21675244)
Just for the record: Raku (née Perl 6) most definitely does not do refcounting. If you want to do serious async programming, refcounting becomes a nightmare to get right and/or a source of potential deadlocks.
Re:Garbage Collection by ridiculous_fish on Sunday December 01, 2019 @01:21AM (#21674165)
Objective-C and then Swift are surely the most serious goes at fast widely used RC languages. Neither requires mutating the reference count on every store, and neither seems at risk of growing a tracing GC.

ObjC had some elision tricks like objc_retainAutoreleasedReturnValue, but more importantly the optimizer was taught about RC manipulation. Swift then extended this with a new ABI that minimizes unnecessary mutations.

The big advantages of this scheme are efficient COW collections and a simpler FFI (very important with Swift). More generally RC integrates better. Imagine teaching the JS GC to walk the Java heap!

Re:Garbage Collection by mpweiher on Sunday December 01, 2019 @12:37PM (#21676638)
> ObjC had some elision tricks like objc_retainAutoreleasedReturnValue, but more importantly the optimizer was taught about RC manipulation.

Cough. Actually, before ARC the ownership rules really kept RC traffic very low, and you could drive it lower still if you knew a bit about how ownership worked in your code ("these will balance and the object is already owned elsewhere...").

ARC just went mad with trying to give guarantees it really had no business making, and then hoping the compiler would be able to remove them again (difficult with message sending).

This caused some amusing bugs, for example a crash in the following method:

   -someMethod:arg and:arg2
   {
       return 0;
   }
How could this possibly crash? All it could possibly do is clear register AX and return.

Well, with ARC enabled and in debug mode, it inserted code to first retain all the arguments, and then immediately release all the arguments. Apparently one of the args was a bogus pointer (framework-provided, so out of our control) and so it crashed.

Re:Garbage Collection by tinus_hn on Monday December 02, 2019 @06:46AM (#21681615)
So the result of your instructions that have undefined behavior turned out to be not what you wanted? That’s hardly a problem with the language.
Re:Garbage Collection by mpweiher on Monday December 02, 2019 @12:37PM (#21684616)
Interesting that

    return 0 
is now considered "undefined behavior".

Whatever.

Re:Garbage Collection by tinus_hn on Monday December 02, 2019 @03:51PM (#21686751)
Obviously the problem is with using objects in the message which are invalid. The compiler may or may not work as you expect and that’s your problem, not the compilers.

You can try to defend yourself by stating the call is done by some framework but that just means the problem is still not in the language, it’s in the framework.

Re:Garbage Collection by mpweiher on Tuesday December 03, 2019 @11:07AM (#21693571)
First, the compiler and framework come from the same vendor, so it's perfectly fine to blame them. Unless you consider things like compilers and frameworks to be independent subjects capable of being blamed.

Second, whether the behavior is defined or undefined, the compiler has no business touching arguments that the code didn't tell it to touch. If it does so, it isn't fit for purpose and can be criticised as being unfit for purpose.

And the C standard is very clear and adamant that being in compliance with the standard is not, and in many ways cannot be, equivalent to being fit for purpose.

Last not least, I think we are probably not going to agree as to whether dereferencing unused arguments is a valid response to the presence of undefined behavior. See

https://blog.metaobject.com/2018/07/a-one-word-change-to-c-s...

Re:Garbage Collection by pjmlp on Sunday December 01, 2019 @04:37AM (#21674698)
So efficient that Swift's RC implementation loses against all major tracing GC implementations.

https://github.com/ixy-languages/ixy-languages

Re:Garbage Collection by jmull on Sunday December 01, 2019 @08:09AM (#21675303)
That project doesn’t compare GC implementations, so it’s probably not that useful here.

Also, the Swift implementation is a bit questionable if performance is a goal. That is, why not try to remove the memory management from the inner loop? Probably the first thing to try is value types instead of reference types, which are more generally preferred anyway.

Re:Garbage Collection by pjmlp on Sunday December 01, 2019 @08:12AM (#21675321)
Sure it does, memory management impacts the performance of the task being achieved, writing an high-speed network driver.
Re:Garbage Collection by jmull on Sunday December 01, 2019 @08:40AM (#21675425)
By that measure, every project is a good measure of GC performance. Is that really a good argument?

I believe all general purpose languages let the code allocate memory and therefore will let you allocate memory in a way inefficient to your task.

Re:Garbage Collection by pjmlp on Sunday December 01, 2019 @09:04AM (#21675524)
The argument is that to eventually write Swift code whose performance matches the competition, one needs to work around ARC's implementation.

Hence why there is so much emphasis on value driven programming alongside protocols at WWDC talks.

Re:Garbage Collection by ridiculous_fish on Sunday December 01, 2019 @01:51PM (#21677108)
My claim was about efficient COW collections and the FFI. The point of COW collections is enabling a simpler programming model.