You could also use async programming to do the same thing in GC-free code. Or just use an arena that can be freed all at once.
You could also use async programming to do the same thing in GC-free code. Or just use an arena that can be freed all at once.
No? Allocations are blocking, "async programming" won't do anything.
Unless you have an async dealloc which does the shunting implicitly, at which point you don't need an async dealloc, you can just have a sync one which shunts the actual dealloc and mandate a background thread. Which means now you're mandating a background thread for freeing memory. And you hope that the load is light enough that implicit thread which you've tasked with all deallocations (rather than just the ones which make sense) keeps up.
> Or just use an arena that can be freed all at once.
That is essentially the same thing, you now have a different allocation strategy for these, except it's a lot more limited and specific.
Modern malloc/free implementations must satisfy requirements such as being scalable. It eliminates any chance to implement blocking deallocation from non-owner threads. A modern implementation already has to be async in some ways. You can check paper behind Mimalloc for example.
Your objects in trees and arrays don't have the same lifecycle?
Quoting GP:
> ... reference counting (RC) have stampeding characteristics similar to GC pauses when releasing large hierarchies e.g. persistent data structures, or large trees of widgets: all the tree is freed synchronously and recursively, if it's large it can be very sensible.
This is mostly where RC & MMM fails. This is also where you are supposed to use arena allocators.
If you have a tree you're constantly adding to / deleting from, you can use a Pool backed by an Arena. At that point you don't use pointers, only indices into the pool. When you want to remove something from the tree, you mark the objects in the pool "deleted" until you want something added back again.
No, there is a nested set of lifetimes.
Take a hierarchy of widgets for instance, if you change a sub-view you're going to reclaim the widgets composing that sub-view, replacing them with widgets of an other sub-view.
Then there's persistent datastructures, where lifetimes are reversed (higher nodes are younger), you update a node, you're going to invalidate all the nodes on the path to that, but the nodes which are not on that path are still alive.
> If you have a tree you're constantly adding to / deleting from, you can use a Pool backed by an Arena. At that point you don't use pointers, only indices into the pool. When you want to remove something from the tree, you mark the objects in the pool "deleted" until you want something added back again.
So you're implementing an ad-hoc GC by hand (and so does everyone else) and making your traversal more complicated.
If there's a GC pointer provided (by the language or a library), in the vast majority of cases it will work well enough and you won't need to waste time on that, you can solve actual issues instead.