Pedantically I’ll say it’s reference counted, and someone else will say that’s still a form of GC and I’ll just save us the mini-thread.
Reference counting has deterministic timing, you can run a deconstructor without registering objects for deletion and running any known finalizers (what you need to do in all GC langs I’m aware of.)
- One object going out of scope may mean calling free once, but it also can trigger calling free billions of objects, even for the exact same object
- Even freeing one object can have largely varying running time, e.g. to coalesce free blocks or, because it happens to be the last block in a virtual memory region, to unmap a block of virtual memory, blocking the program potentially for an arbitrary time
- With garbage collection (as with reference counting), lots of the overhead of objects going out of scope can be moved onto a specialized thread.
> you can run a deconstructor without registering objects
Not requiring finalizes does make reference counting easier, yes. The downside is have to store the reference counts somewhere, and keep them up to date (enough)
"- One object going out of scope may mean calling free once, but it also can trigger calling free billions of objects, even for the exact same object
- Even freeing one object can have largely varying running time, e.g. to coalesce free blocks or, because it happens to be the last block in a virtual memory region, to unmap a block of virtual memory, blocking the program potentially for an arbitrary time"
So, like C, C++, or anything else that you wouldn't call garbage collected.
Well, GC has indeterminate timing in and of itself. Reference counting does not. It can still trigger indeterminate timing if the destructor calls free, or if the "thing" going out of scope is a pointer, but that's on the destructor or the pointer, not on reference counting per se.
> but that's on the destructor or the pointer, not on reference counting per se.
It is on reference counting per se. If the reference count of a reference goes to zero, the runtime has to make the memory available for reuse. That’s what I called ‘calling free’.
Also, about “GC has indeterminate timing in and of itself”. Again: define what you mean by it. Yes, The timing of allocating an object can vary depending on the state of your memory allocator, but that’s the same with reference counting.
(even allocating an object on the stack and then writing to it can have variable timing on many OSes. If you look really close, even decreasing a stack pointer can have variable timing on modern pipelined CPUs due to data dependencies)
And as I said, the GC work to find and reclaim unreachable objects can run on separate thread(s).
I think I understand you now. You don't do reference counting for something "on the stack" (in C++ terms), you only do it for something on the heap. Things on the stack can have destructors, but that gets called when the stack frame goes out of scope. So anything reference counted, when the count goes to zero, will not only have its destructor run, but will also be deallocated on the heap (calling free).
And then whether you blame that on reference counting or garbage collection or heap allocation is kind of an arbitrary distinction.
Reference counting has deterministic timing, you can run a deconstructor without registering objects for deletion and running any known finalizers (what you need to do in all GC langs I’m aware of.)