7 ms·
I too keep hearing this repeated but without empirical support. Same goes for the idea that garbage collection can be faster than manually managed memory. In p
by darksaints 6y ago
I too keep hearing this repeated but without empirical support. Same goes for the idea that garbage collection can be faster than manually managed memory.
In practice, PGO has been the best possible compilation regime that I have ever found.
- pjmlp 6y agoIt goes both ways actually.
- saagarjha 6y agoIt's easy to come up with cases where you can do better than a fairly reasonable programmer: think of a loop that allocates at the top and frees at the bottom with enough stuff happening in between that the allocator doesn't just hand you back the same memory from a cache. Depending on the runtime, it might be better to just bump allocate and garbage collect all that memory at the end. You can find the benchmarks that'll show it, too. In reality, with actual applications garbage collectors have "good enough" performance with many benefits such as correctness and ease-of-use, but manual memory management done by a skilled programmer will outperform it.
- dialamac 6y agoI think that’s my point. I get that JIT can produce faster code, I get that java is good enough for most things. But if you’re already in the performance critical regime there are other things you have to do where just having JIT available isn’t some magic bullet.
- kipply 6y agoA possible magic solution is to load a JIT state from a previous execution and have good manual-optimization features to be like PGO. This would give JITs best of both worlds with being able to get to a strong peak performance and also not requiring manual tuning
- littlestymaar 6y ago> Same goes for the idea that garbage collection can be faster than manually managed memory. It's really workload dependent and depend a lot of the GC involved (a pretty dumb one like Python's or Go's won't get you anything performance wise), but a copying collector can achieve allocation way faster than a regular heap allocator (the allocation can be almost as cheap as allocating on the stack). If you can't avoid boxing and your objects aren't all long-lived, you can run circles around a program not using such a GC.
- darksaints 6y agoYes, allocation can be incrementally be made cheaper with a copying GC. But you have to realize that it still comes at a cost, and allocation speed isn't always a bottleneck. You have a runtime process intercepting your code state, scanning and analyzing your heap and making a decision to keep, copy, or free. For anything larger than a trivially small object graph, that additional processing can easily overwhelm any incremental allocation speed benefit that you get. I get that it is theoretically possible for GC to be faster, but I literally have never seen it pan out in practice.
- tsimionescu 6y agoIm very skeptical that the comparison really makes sense. Programs written in GC languages are so different in their allocation behavior from those written in manual memory languages that I don't think you can meaningfully compare them. And comparing regular C++ with Boehm GC is probably not that interesting, as Boehm is extremely limited by the semantics of C++. And whichever way you look at it, the GC doesn't really have to outperform manual memory management to be extremely useful. It just has to be close enough, the correctness guarantees alone make it worth it as long as the performance difference is not too large, in many domains, not to mention the productivity boost and program readability.
- darksaints 6y ago> And whichever way you look at it, the GC doesn't really have to outperform manual memory management to be extremely useful. It just has to be close enough, the correctness guarantees alone make it worth it as long as the performance difference is not too large, in many domains, not to mention the productivity boost and program readability. I agree with all of this. But it is a very different argument than the theoretical argument that garbage collection can be faster than manual memory management. Rust, for example, is manually managed or compiler managed, depending on how you look at it. But its semantics are extremely crude and naive: allocate on creation, free once an object leaves its current scope. There is no optimization of heap fragmentation, there is no optimization of large bulk frees...the compiler literally just inserts the malloc/free statements for you in a static location that you don't get to choose. And despite the crudeness of its memory allocation behavior, it runs circles around garbage collected languages all day long. Even fast ones...I have done more than a handful of comparisons between Scala, Java, Go, SML (MLTon), OCaml, F#, and Rust...and Rust always comes out on top. That doesn't mean the performance advantages are worth the extra pain of dealing with a borrow checker...for most of my code, I default to Scala for all the reasons you've mentioned. But I don't delude myself into thinking it is faster.