> I think a lot of people just want to be able to discuss different areas of the automatic memory management design space separately, and maintaining the distinction between reference counting and garbage collection (meaning tracing GCs) lets them do that.
The problem is that there are many differences in memory management techniques that offer different tradeoffs, and the difference between refcounting and tracing is not necessarily the biggest of them.
For example, one of the most important distinctions in memory management is whether it optimises for footprint or speed (or some compromise), and the line isn't where people who don't understand memory management think it is. It can matter (often a great deal) whether you determine that an object is dead dynamically (say, by counting references) or statically (by manually writing free or by having the language track lifetimes), but it doesn't matter as much as whether or not the mechanism needs to know when objects are dead in the first place. So reference counting, manual free, static lifetimes, and even non-moving mark-and-sweep tracing collectors (like Go's) generally optimise for footprint at the expense of speed (although different allocators can have some control over that tradeoff), while arenas and tracing moving collectors optimise for speed at the expense of footprint (although here, too, they have some control over the tradeoff). So the line for this super-important tradeoff is between [manual, static, refcoutning] and [arenas, moving tracing]; non-moving tracing collectors are somewhere in between but may be closer to the first group.
People who don't understand memory management and may not have a lot of experience in low-level programming sometimes think that manual or statically-determined freeing must be fast because low-level languages, which inexperienced people think are fast, use them. In fact, low-level languages have some concerns that are much more important than speed and that preclude them from optimisations such as moving pointers. To get around that performance handicap, these languages try to avoid using their heap memory management as much as possible because they're using a rather slow technique because of their constraints.
"Speed" is also ambiguous between latency and throughput. You seem to be using "speed" here as a synonym for throughput. Because of Little's Law, the memory consumed by deallocated objects is directly proportional to deallocation latency, so "low footprint" also generally means "low latency", while increasing throughput by amortizing deallocation overhead at the expense of latency increases memory usage for the same reason.
> so "low footprint" also generally means "low latency"
Not anymore.
You're absolutely right that one of the reasons moving collectors were not used more widely was that, while their throughput was always very impressive, their latency wasn't that great, but that changed a few years ago.
E.g. Generational ZGC in OpenJDK (released in September '23) introduces hiccups or "pauses" that are not dependent on the size of the liveset and are no larger than latency hiccups introduced by the OS (assuming no realtime kernel), i.e. <1ms (and typically <<1ms) up to heaps of 16TB. In fact, the latency can be smoother than approaches that have an explicit free operation and require maintaining a free list, as freeing a large object graph can be quite slow and occur in surprising places.
So modern moving GCs no longer have a latency penalty, but this is newer than even ChatGPT.