12 ms·
GC every frame? Jesus. Gamedevs jump though hoops to avoid it.
by nicetryguy 5y ago
GC every frame? Jesus. Gamedevs jump though hoops to avoid it.
- __s 5y agoProbably added after profiling on that system found that the GC pauses would fit within frame budget, whereas not running it every frame would have a long pause eventually drop frames
- jonny_eh 5y agoThis! If you GC every frame, you can almost guarantee that it runs fast enough to not cause a frame skip.
- kaba0 5y agoOnly true for Java runtimes at the time. With modern JVMs with generational GCs, it is detrimental even. Profile it, and only let allocation rate increase to an acceptable level that can be reclaimed easily. Or nowadays one can use a low latency GC as well.
- zlynx 5y agoYour other choices are: - Never GC via using object pools. This code is nastier than C++ because Java is not intended to be used this way. - GC whenever needed randomly. The game will just pause occasionally. Very annoying as a player. - Write the actual game in C++. Make a few JNI calls here and there. On feature phones I only remember this being possible for some vendor apps.
- banana_giraffe 5y agoIf these phones were still around, I'd imagine there'd be another option now: - Write your game in C++ and transpile it to Java using some fancy framework that dances around never using GC.
- kllrnohj 5y agoYou'd have to do something like allocate a single byte[] for everything you'll ever need, and reading & writing data would just be a constant tax since you can't just in-place cast that to an int or whatever. It wouldn't be very fun.
- zlynx 5y agoBut it would be transpiled so the programmer would never need to look at the very ugly stuff. The idea reminds me of the original asm.js
- kaba0 5y agoDepends on when. If we are talking about modern day JVM, than even the non-latency optimized default GC would have <10ms stop-the-world pauses for up to gigantic allocation rates, much less for the presumably minor one of a simple game. And then there are two latency optimized ones, Shenandoah and ZGC, with the latter having <1ms, meaning that your OS introduces more latency with thread switches. So I think writing a game while profiling allocation rates and paying a bit of attention to not spam new everywhere, one should get decent performance without any framedrops. At most, optimize the hot loops with primitives, arrays.
- CodeArtisan 5y agoThese games are turn and grid based like Legend of Grimrock or Chess where input lag is much less important.
- kalleboo 5y agoThese phones had like 1 MB, 2 MB, 4 MB of RAM. And these were 3D-accelerated games running on them. A GC language was definitely the wrong choice for the platform, but J2ME was the industry standard because portable. So if you're allocating a dozen objects in a frame it's best to GC them in the same frame or you're going to lose tens of frames later. Even in modern times, for the longest time Android Java apps had laggy scrolling due to GC hitches that the refcounting iOS Obj-C apps avoided.
- pjmlp 5y agoRefcounting has glitches as well.
- astrange 5y agoThe refcounting isn't so bad but freeing and running destructors can pause. There's also memory fragmentation from not having a compacting GC. It's all fixable though.
- kaba0 5y agoThough nowadays GC is also “fixable”, and probably more performant than refcounting, at least for non-single-threaded code.
- astrange 5y agoCross-thread refcounting is not that common and the CPU has very fast atomics anyway. It's still a better tradeoff than having to sweep (which might need to page in), make all pointers visible, accept the occasional peak memory increase, etc.
- kaba0 5y agoWhat are the options for sharing an object between threads then? And even with having good atomics, it is a very significant overhead. Also, the primary reason for modern GCs having significantly better performance than refcounting is that with GC one can move the majority of work to another thread, letting them continue the work. Refcounting is good for some simple programs where ownership is not trivial, and the language doesn’t support a GC/or when memory is constrained, etc. But it is not an accident that high level languages with GC doesn’t choose refcounting, and having the cost of destruction at the given thread is just one point, afaik circular references are similarly not an easily solved problem. And basically with every single “solution” to these problems you are moving towards a full-blown GC.