> will use arena / bump / slab allocators.
While not always the case, it is often the case that a good GC will beat all of those. A generational copying GC with parallel collection will treat most allocations as pointer bumps. Giving them the speed of a bump allocator with periodic fragmentation fixes when collection happens. It will beat both slab and arena allocators.
> naive code and you don't get to write naive code if you care about speed / memory usage.
I mean, you can certainly always implement a GC in C (most GCs are implemented in C/C++). Which does suggest that anything you can do with a GCed language can ultimately be replicated in a memory managed language.
However, the point of a GC is that naive code IS faster and easier to reason about. You don't have to create and manage elaborate data specific object pools in order to get the same speeds as if you did.
The other thing to consider about GCs is they enable algorithms that are really hard to replicate in memory managed languages. Concurrent algorithms are WAY easier to reason about because you don't have to wrap your head around object lifetime with thread lifetime.