6 ms·
True. This is why any serious game running on a VM with GC would avoid any kind of per-frame memory allocation and use arena allocators instead. The whole prem
by w0utert 7y ago
True. This is why any serious game running on a VM with GC would avoid any kind of per-frame memory allocation and use arena allocators instead.
The whole premise of a GC to save you from thinking about memory allocation is moot if it comes to real-time sensitive tasks, there it makes things harder instead of easier. A reference counting system is much better IMO, even though you may be able to get higher absolute throughput with GC, at least the small overhead you incur is stable and predictable.
- masklinn 7y ago> True. This is why any serious game running on a VM with GC would avoid any kind of per-frame memory allocation and use arena allocators instead. The problem is having the VM allow and support that usage, and the JVM definitely is not best-of-class there. See ixy[0] from a few months back where the researchers / developers didn't manage to get under > ~20 bytes of allocation per forwarded packet in Java. [0] https://github.com/ixy-languages/ixy-languages https://github.com/ixy-languages/ixy-languages
- _ph_ 7y agoI don't think the idea of GC is to save you from thinking about memory allocation. Actually, not thinking about memory allocation is a great way to create very slow programs, independant of whether you us an GC or manually free memory, though modern GCs keep the performance penalty reasonably low. Still, you want to think about memory allocation, so that you don't allocate inefficiently. What GC delivers is first of all the guarantee of correctness, a pointer is either nil or points to a validly allocated memory. Also, it removes most needs of bookkeeping. That simplifies programs and especially allows to write clean APIs, where functions are fine to allocate reasonable amounts of memory. But wherever there are large parts of memory required, especially with a clear lifetime, I think a lot about memory allocation and even in a GC language I try to reuse memory wherever that makes sense. So for a game engine, there should not be much need for allocation during the run time of a "level" and thus GC pauses should only happen between levels.
- barrkel 7y agoNot thinking about ownership over references to heap allocations is very very much the big productivity win from GC. Memory safety is usually an additional bonus, but it's a distinct thing; it's possible to have (conservative or refcounting) GC without memory safety and vice versa.
- zozbot234 7y ago> Not thinking about ownership over references to heap allocations is very very much the big productivity win from GC. I very much doubt that this is a big _productivity_ win. Languages in which it is idiomatic to "think about ownership over heap allocations" (C++, Rust) aren't obviously less productive than comparable languages where such thinking is not so idiomatic (C, Java, .NET, ObjC, Swift etc.). It's somewhat common to use refcounting (shared_ptr<>, etc.) in the more exploratory style of programming where such "thinking" is entirely incidental, but refactoring the code to introduce proper tracking of ownership is quite straightforward, and not a serious drain on productivity.
- brighteyes 7y agoGC might not be a productivity win for you, but for many people it definitely is. I'm pretty sure that's true for the great majority of software developers, but of course they don't even use a non-GC language! Part of the reason they don't is that productivity. Not that they chose it personally for that reason, but e.g. historically enterprise code moved to Java and C# for related reasons. (I also agree there are people that are equally productive in non-GC languages, or even more - different people have different programming styles.)
- zozbot234 7y agoEnterprise code moved to Java (and later C#) for memory safety, period. The level of constant bugginess in the C++ codebases just made them way too messy and outright unmanageable.
- enhray 7y agoI’ve heard horror stories about reference counting performance cliffs caused by avalanche deallocations, which are hard to predict.
- w0utert 7y agoThey are not harder to predict or control than garbage collection, and have the benefit of being completely deterministic. Of course you can always come up with some pathological case that would trigger a 'deallocation avalanche', but you would almost have to deliberately make an effort to run into a thing like that. And if you do, it's typically very easy to fix these kinds of things. In the Objective-C era before automatic reference counting, you had these things called 'autorelease pools' which allow pretty straightforward control over deallocation. I think the same thing is still possible in ARC Obj-C and Swift.
- barrkel 7y agoPer-frame allocation would be very cheap with a tuned generational GC run every frame, as nothing would be live at the end of the frame and thus tracing would take almost no time. Of course the same would be true of an arena allocator, at the cost of needing to classify every allocation accurately.
- LessDmesg 7y agoReference counting is not better, it's a poor man's GC. Reference counting means: 1) instruction pollution from all the refcount updates and their synchronization 2) circular references, ie memory leaks 3) too much time spent freeing memory (whereas a generational GC spends time on live objects only) 4) memory fragmentation and hence slow allocation (whereas in a normal GC allocation is just O(1)
- saagarjha 7y ago> circular references You can solve this with weak references.
- w0utert 7y agoLanguages like Swift and Objective-C hide the reference counting for you, so 'instruction pollution' is not really something I care about. The overhead at the instruction & memory level is fairly minimal for these language too, by means of using tagged pointers. I'm pretty sure the compiler is smart enough to factor out reference counting for complete sections where it can determine objects can impossibly go out of scope (e.g. sections where aliasing can be ruled out, and all assignments are to locals, such as in many loops). Circular references can be a problem, this is just something you have to live with and design for, just as in languages with manual memory management. In the typical cases where this can be a problem (graphs of objects) its very straightforward how to fix them using weak references. I don't understand point 3 and 4 and why they would be a property of reference counting for memory management. They both seem completely orthogonal problems that have nothing to do with the mechanisms that decide when to free memory. Anyway, my original point was not that reference counting is perfect, or even more efficient compared to garbage collection. Just that it is predictable and deterministic, which is very often much more important, especially for code with real-time constraints.