Remix.run Logo
▲ raverbashing 4 hours ago

I don't get why people do not prefer reference counting, it has more predictable runtime performance

(though of course a swap is a swap - but you can "trigger" it depending on your memory or file access pattern)

▲Findecanor 2 hours ago | parent | next [-]

Reference counting has high runtime overhead, especially atomic reference counting with multiple threads. If you overwrite a pointer, you'd need to also look up and update two counts and do all that in a manner that is effectively atomic -- and that is complex on current hardware. I've heard that Swift programs could have as much as 40% runtime overhead from ARC.

I still think that reference counting is promising though. First because it meshes well with static analysis memory-management techniques such as inference of uniqueness and borrowing -- that can optimise away RC altogether. (and Swift's compiler already does some of that). I have not seen any work that could optimise away tracing GC in a similar way. Second, because I believe that it would be possible to design hardware with object-memory addressing that would performs atomic reference counting with no additional runtime cost.

▲pjmlp an hour ago | parent [-]

That is exactly what escape analysis does, granted the way it is done across implementations varies.

Such hardware has been designed in the past, Lisp machines, Ada machines, the famous iAPX 432 Intel's failure.

▲xxs 4 hours ago | parent | prev | next [-]

ref counting is expensive in multi-threaded applications. Overall it would have worse performance. When it comes to predictability: deallocating a linked list (for instance) would have to deallocate all of the elements. Dealing with reference cycles is also not simple, either.

▲raverbashing 2 hours ago | parent [-]

Honestly some (container) objects makes me think that they should be "parent obj management only"

▲groestl 4 hours ago | parent | prev | next [-]

Overhead per allocation, if you care about that, and reference circles.

▲pjmlp 2 hours ago | parent | prev | next [-]

Because the industry has plenty of experience with referece counting as the very first GC algorithm, already in the early 1960's, in early Lisp implementations, BASIC, Cedar, and several other languages.

The predictable runtime performance is also a myth, because they never take into account the use of NUMA memory, lock contention, possible stack overflow and stop the world in the case of cascaded deletions in naive implementations.

▲raverbashing 2 hours ago | parent [-]

Lock contention yes, it's fundamentally a RC issue, but makes me think per-thread objects make more sense

I'm not sure most GC implementations worry about the rest neither (as by the several complaints we see going around)

▲pjmlp an hour ago | parent [-]

The ones across several JVM implementations (there is a world beyond OpenJDK), and the CLR certainly do.

▲raverbashing an hour ago | parent [-]

Yes, and the fact you have to have a "special GC" for your case makes me wonder that those constraints are not so obvious.

(makes me wonder who's buying those - things like Azul, etc)

▲pjmlp 13 minutes ago | parent [-]

Places that were doing C++, but found out that the right GC, and JIT compiler, can achieve good enough performance for their business case.

There is nothing "special GC" about it, the failure is to assume there is only one way to implement GC algorithms, as if there is only one way to implement hash tables, tree re-balancing algorithms, .... and then place all languages into the same bucket.

Then we have the modern times with AI driven code generation, where no one cares how their agents are actually doing the work, with what kinds of resource management approaches.

▲bheadmaster 4 hours ago | parent | prev [-]

> more predictable runtime performance

Not really, reference counting can cause a single object deallocation to trigger an arbitrarily long chain of deallocations.

▲Findecanor 2 hours ago | parent | next [-]

Immediate reclamation, yes. There do exist a number of reference-allocation algorithms that performs deferred reclamation similar to how tracing GC does.

▲amelius 2 hours ago | parent [-]

Yes, but that still leaves the circular dependency problem.

▲raverbashing 2 hours ago | parent | prev [-]

Yes but then you can move your deallocation out of the critical path

Variable time yes but you know when you're going to pay it

(I mean yes you can put your gc.run() there as well, but it might not give you the results you want)