Agreed. I suspect a more useful distinction would be "...can't match the performance of languages that facilitate stack allocation" - the main advantage comes from locality of reference rather than tighter heap management. There's a separate point that could be made about the memory headroom needed for GC to work well, but (sadly) I don't think many people think of memory-efficiency as a performance metric these days.
I'm not sure about your
> So if you're using a GC you probably program in a different way, eg using more shared immutable structures
This is definitely not the case for mainstream GC languages like Java, which have truly awful support for immutability, to the point of having to write a separate type if you want it.
Sorry if OT, but the nand2tetris course really brought the benefits of stack vs heap allocation into stark relief. As part of the course, you have to implement a compiler and OS, including malloc/free [1].
You can see how local variables just push something onto the stack, which is a small number of CPU instructions, while malloc is a big function, each step of which translates into many instructions, and which also has to deal with iterating through a data structure to find a big enough block.
I'm not sure about your
> So if you're using a GC you probably program in a different way, eg using more shared immutable structures
This is definitely not the case for mainstream GC languages like Java, which have truly awful support for immutability, to the point of having to write a separate type if you want it.