4 ms·
You can get the idea that a GC has minimal impact on performance when you just look at things like how fast the GC runs, or what % of time is spent in GC, but t
by jackmott42 4y ago
You can get the idea that a GC has minimal impact on performance when you just look at things like how fast the GC runs, or what % of time is spent in GC, but that only represents a portion of performance implications, there are lots of indirect effects:
1. More memory is used, which means more CPU cache evictions happen
2. There will be things the language won't let you do, because it is garbage collected
3. There will be extra FFI costs, like when making OS calls or calling into other languages
4. There will be cultural tendencies, if a language uses GC, the people who designed it and used it are less likely to be interested in compromising other things for extreme performance. Example: If a linq query has overhead in C#, and they have to make a breaking change to eliminate it, they will not. In Rust if an iterator is slower than what hand coded C would be, its a bug, and every effort will be made to fix it if possible.
That said, it is still the case that most programs aren't penalized by GC much. But people do still work on operating systems, games, databases, video editing tools and such where getting great performance is really important.
- deleted 4y ago[deleted]
- TylerE 4y agoMalloc isn’t free, either.
- 59nadir 4y ago`malloc` doesn't make up a meaningful percentage of performance-oriented software's execution time. Most of those programs bulk allocate and manage memory internally, so the cost of `malloc` isn't a relevant argument against managing memory manually. Indeed it's entirely possible to write a program that doesn't ever use `malloc` while still using allocations internally, from a stack allocator. The point isn't to `malloc` every single allocation and pair them up with `free` calls; it's to use allocators that alleviate that burden while also allowing you to pick an allocation pattern that makes sense for the use case (and internal use cases). As an example, if your total memory usage for your program could be determined at startup to be 1GB, then you could allocate 1GB up front and allocate from that memory in the rest of the program, guaranteeing that nothing after startup ever goes to the OS for memory. Overall it's much easier to write obviously efficient software in Zig than it is in Rust, IMO, and it's much easier to see at a glance that something won't behave stupidly when it comes to allocation and deallocation. To be fair, this is something Zig has over most other languages as well, so it's not exactly specific to Rust.
- gpderetta 4y agoAnother hidden penalty of some (but not all) GCs is that they can't handle interior pointers so anything that is addressable need to be separately allocated. So not only you have more allocations to track and more space and time overhead, you also add indirections where they are not needed. Of course a Sufficiently Smart Compiler can remove the overhead, but well...
- arc619 4y agoNim uses stack allocated value types by default, and GC (or ptr) is an optional tag to the type definition. GC types use borrow & move analysis like rust (not as good yet tho) so it can elide GC work when possible. GC is also not stop-the-world, deterministic (assuming no cycles), and configurable to soft realtime performance. So you dont need to use the GC, but it will give you RAII if you want without needing to perform the dance of the borrow checker. BTW Nim is also closing in on Rust's borrow checking semantics, too!
- arc619 4y agoAlso, aside from the fact GC is optional in Nim, what are you thinking of that cant be done with a GC?
- elcritch 4y ago> That said, it is still the case that most programs aren't penalized by GC much. But people do still work on operating systems, games, databases, video editing tools and such where getting great performance is really important. This statement simply isn't true though, at least in the general sense. Sure, for old school atomic RC and compilers that didn't do RC elision etc it might've been true. But we can and have made smarter compilers, just like Rust has gotten smart about life times. Like @netbioserror I use Nim, but for embedded and real-time stuff. There is a minimal overhead (one machine word per allocation), but using Nim's ARC "memory management system" gives me results comparable to Zig or Rust though with much less work. Technically ARC without the cycle collector isn't a GC. There's no reason D and other languages with "memory management" couldn't do similar RC based systems. As the compilers get smarter it approaches the same result as Rust's manual lifetime analysis. In many cases compilers can be smarter than human programmers about memory. Even then, there's occasions where in Nim one can and will reach for manual memory allocations. It's easy to do when wanted. > 2. There will be things the language won't let you do, because it is garbage collected There will be things that systems like Rust's lifetimes makes harder / less performant as well: https://ceronman.com/2021/07/22/my-experience-crafting-an-interpreter-with-rust/ https://ceronman.com/2021/07/22/my-experience-crafting-an-in... > 3. There will be extra FFI costs, like when making OS calls or calling into other languages For generational GC's this is true, but for RC systems not as much. > There will be cultural tendencies, if a language uses GC, the people who designed it and used it are less likely to be interested in compromising other things for extreme performance. This is certainly a thing. However, cultures can vary a lot. For example Nim provides zero-cost iterators as well as minimal-cost "closure" iterators. Now Nim's string libraries do a lot of copies by default which makes it easy to ruin performance. However, there's an open RFC to provide CoW strings to reduce this overhead. There's also the new `lent` type too. After all, it's used in games and embedded so there's desire for that. Certainly if your language is tedious about memory management, you'll spend more time on it. Though as an end user I'm not sure I've noticed a practical difference between Go and Rust programs as compared to C#/Java applications. The latter I avoid running if possible because of their general bloat.
- kaba0 4y ago> More memory is used, which means more CPU cache evictions happen The first part is true, and the second part is sort of true, but it may or may not matter. The order of magnitude speedups that good cache usage can cause only happens when you are having a small hot loop working over a huge amount of data that has an easy to guess access pattern (e.g. serial). I am not convinced that your ordinary program would have too many such loops and thus that it would have a huge speed up were it rewritten in C from a managed language. > There will be things the language won't let you do, because it is garbage collected There are always escape hatches > There will be extra FFI costs, like when making OS calls or calling into other languages Do you mean like GC barriers and such? But we do agree on your last paragraph, and sure low-level languages will always be needed. But the niche where they are irreplaceable are very small, if we are pedantic OS and games are also not necessarily to be written in them (see Microsoft’s singularity, the latter has plenty of examples)