3 ms·
There are a lot of cases where unique and shared pointers are no good solution, and where a GC would help (e.g. when there is no clear ownership hierarchy but a
by Rochus 3y ago
There are a lot of cases where unique and shared pointers are no good solution, and where a GC would help (e.g. when there is no clear ownership hierarchy but a lot of mutual dependencies between objects). And not to forget that smart pointers come with a non-negligible cost.
- HarHarVeryFunny 3y agoshared_ptr essentially provides reference counted garbage collection. Sure there's a small overhead to smart pointers, but in 2024 it's a very odd application where you are compute bound and pointer dereferencing is the reason!! Garbage collection has an overhead too of course, since there is a major cost to discovering what can be freed, while the cost of doing this with smart pointers is zero.
- Rochus 3y ago> Sure there's a small overhead to smart pointers Not so small, and it has the potential to significantly speed down an application when not used wisely. Here are e.g. some measurements where the programmer used C++11 and did everything with smart pointers: https://github.com/smarr/are-we-fast-yet/issues/80#issuecomment-1672960484 https://github.com/smarr/are-we-fast-yet/issues/80#issuecomm.... There was a speed down between factor 2 and 10 compared with the bare-bone C++98 implementation. Also remember that smart pointers create memory leaks when used with circular references, and there is an additional memory allocation involved with each smart pointer. > Garbage collection has an overhead too of course The Boehm GC is surprisingly efficient. See e.g. these measurements: https://github.com/rochus-keller/Oberon/blob/master/testcases/Are-we-fast-yet/Are-we-fast-yet_results_linux.pdf https://github.com/rochus-keller/Oberon/blob/master/testcase.... The same benchmark suite as above is compared with different versions of Mono (using the generational GC) and the C code (using Boehm GC) generated with my Oberon compiler. The latter only is 20% slower than the native C++98 version, and still twice as fast as Mono 5.
- HarHarVeryFunny 3y agoIf your application is fighting the language you've selected so hard, then maybe the language choice was a poor one to begin with. Modern C++ is a very high level language - very powerful when it's a good match for your needs. If you need zero overhead memory management then garbage collection isn't going to be the answer either - you need application specific arena allocators, reuse pools, etc. You seem to be focusing on a very odd set of performance requirements where the overhead of garbage collection is just right, C++ too inefficient, and the need to go full custom not needed.
- Rochus 3y ago> You seem to be focusing on a very odd set of performance requirements It's a standardized benchmark suite used to compare different languages, thus focusing on similarity and comparability of the implementation. It's especially suited to compare GC and non-GC implementations.
- AdieuToLogic 3y ago> Garbage collection has an overhead too of course, since there is a major cost to discovering what can be freed, while the cost of doing this with smart pointers is zero. Run-time cost for GC can be minimized, if not completely obviated, by having the collector run on a processor other than those allocated for system use. One such example of this strategy is the JVM Concurrent Mark Sweep[0] GC algorithm. 0 - https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/cms.html https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gc...
- HarHarVeryFunny 3y agoThe other poster in this thread is advocating for GC as an alternative to C++ smart pointers in cases where the overhead of these is unacceptable, so giving up an entire processor/core to run GC would be a non-starter (in this performance-driven use case).
- adev_ 3y ago> where a GC would help (e.g. when there is no clear ownership hierarchy but a lot of mutual dependencies between objects) Not really. This is a straw man argument. Having large graph of object with mutual dependencies represented as references to each other is almost all the time a code smell and a problem of design. It is terrible for cache locality, terrible for memory fragmentation and will bring even the best GC on its knees. The way to handle that is to use Entity Component System [^1] or a SOA structue with indexes. In fact every mature game engine or serious Graph Representation library (which are specially design to deal with these cases) will do exactly that. [1] https://en.m.wikipedia.org/wiki/Entity_component_system https://en.m.wikipedia.org/wiki/Entity_component_system
- Rochus 3y ago> This is a straw man argument. Of course it can also be done without a GC. > is almost all the time a problem of design There are even cases where this design is unavoidable to solve the problem.