- 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.
- Write your game in C++ and transpile it to Java using some fancy framework that dances around never using GC.
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.
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.
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.
It works fine, it’s just not done that often. (Specifically contended refcount changing isn’t done, which is why having fast uncontended atomic helps.) Transferring between threads happens and just works.
ObjC has explicit weak pointers and ways to move destructors to another thread and it all works. Though you could use C# or JavaScript in your app, many people do.
Actually, PHP and Python do use refcounting internally, I think PHP only GCs on exits from functions…
https://github.com/ixy-languages/ixy-languages
https://blog.metaobject.com/2020/11/m1-memory-and-performanc...
Also C# can do everything that Objective-C is capable of, provided one actually knows how to use the language.
CPython uses a mix of refcounting with a cycle collector tracing GC, other Python implementations use tracing GCs.
The language does not specify GC semantics and counting on them is a recipe to break code when moving across implementations.