Show HN: A pure reference counting GC in Go
github.com
github.com
Specifically, when I work in a reference-counted environment, if an object has a resource, like an open file, or a socket, I don't need to do anything special when I'm done with that object. The reference count predictably drops when I'm done with the object, and its destructor cleans up its resources.
In contrast, because garbage collection is non-deterministic, in a garbage collected environment, I have to use extra special care when an object uses a resource (file, socket, ect,) that needs to be released at a predictable moment.
Because: If, in a garbage collected environment, the rule of thumb is to "make sure you don't have circular references to your resources, (files, sockets, ect,)" this would dramatically simplify resource (not memory) management!
Name string
Rc int
Crc int
Color string
Buffered bool
Children []*Object
Freed bool
isAcyclic bool
as those seem to have quite a bit of overhead for an object.There are a plenty of steps to make it into usable gc.
But the threadsafe one does have a lot of raw edges, and I couldn't get that one working.
I think assemblyscript has implemented it. Something you might be interested to explore
edit: I fixed the import cycles and got it to build, but now the tests don't pass. The more of this code I read ... the worse it gets. Why is this on top of HN?
Also reference counting only applies to a tiny subset of Objective-C data structures, classes derived from NSObject using Cocoa retain/release patterns.
If you add Swift to the soup, there is still quite some work to do regarding performance,
https://github.com/ixy-languages/ixy.swift/blob/master/perfo...
The other, even bigger OS, is running on tracing GCs.
And Windows is running on a mix of reference counting and tracing GC.
The downside is, of course, that it requires much more care (to avoid cycles)
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
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.
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.
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.
Also there are tracing GC that operate with local heaps.
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.
Adding GC to the Android platform was a stupid move. The Android UI is still janky compared to iOS, and GC is not the only reason why, but it's a significant reason. Android devices also eat battery like it's going out of style compared to iPhones and iPads. Again, GC is not the only reason for this but it factors in.
So they did the only possible exit, automate the manual retain / release Cocoa patterns on the compiler, and sell a marketing story about ARC and how GC is bad.
Pity that Borland and Microsoft haven't done the same about their compiler support for COM RC, done years before.
Android UI is janky due to bad coding practices, specially doing too much on UI thread.
Our phones are super computers compared with Lisp Machines.
If you want to start counting devices sold, it is pretty clear that tracing GC has won, specially when we had any kind of device with a web browser on it.
https://iacoma.cs.uiuc.edu/iacoma-papers/pact18.pdf has 42% on average, and halves that using their modification.
If not, there's room for more research.