logoalt Hacker News

pronyesterday at 1:07 PM2 repliesview on HN

> If you really want to call that a GC you should at least make a huge distinction that it works at compile time: the generated code will have drop calls inserted without any overhead at runtime. But no one calls that a GC.

Except for the memory management literature, because it's interested in the actual tradeoffs of memory management. A compiler inferring lifetimes, either automatically for some objects or for most objects based on language annotations, has been part of GC research for decades now.

The distinction of working at compile time or runtime is far from huge. Working at compile time reduces the work associated with modifying the counters in a refcounting GC in many situations, but the bigger differences are between optimising for footprint or for throughput. When you mathematically model the amount of CPU spent on memory management and the heap size as functions of the allocation rate and live set size (residency), the big differences are not whether calling `free` is determined statically or not.

So you can call that GC (as is done in academic memory management research) or not (as is done in colloquial use), but that's not where the main distinction is. A refcounting algorithm, like that found in Rust's (and C++'s) runtime is such a classic GC that not calling it a GC is just confusing.


Replies

pronyesterday at 11:20 PM

P.S.

I should add that the JVM (and Go) also infers lifetime for non-escaping objects and "allocates" them in registers (which can spill to the stack; i.e. `new X()` in Java may or may not actually allocate anything in the heap). The point is that different GCs involve compiler-inferred lifetimes to varying degrees, and if there's a clear line between them is less the role of the compiler (although that's certainly an interesting detail) and more whether they generally optimise for footprint (immediate `free` when the object becomes unreachable) or throughput (compaction in a moving-tracing collector, with no notion of `free` at all).

There are also big differences between moving and non-moving tracing collectors (Go's concurrent mark & sweep and Java's now removed CMS collector). A CMS collector still has concepts that resemble malloc and free (such as free lists), but a moving one doesn't.

ceteiayesterday at 2:52 PM

> A refcounting algorithm, like that found in Rust's (and C++'s) runtime is such a classic GC that not calling it a GC is just confusing.

But is it not easy to opt out of in C, C++, Zig and Rust, by simply not using the types that use reference counting?

And how does your performance analysis consider techniques like arenas and allocating at startup only?

show 1 reply