4

This question extends from these questions:

Well, a JVM running on a server is well optimised, I know. Programs like Minecraft server runs pretty smoothly with a little pause time every few seconds(it's still well over 2-5ms, so that's still quite a lot for some applications). If I'm writing apps like that, I'd have no trouble getting sleep at night to think about if I should implement object pooling for that Java app that I should make. But this time, I'm making an Android app.

My app will create a considerable number of POJOs, specifically vector/quat that have 3/4 double primitives as its member(might fall back to float if necessary) every 40TPS game tick. Purpose of them being algorithms like line-plane intersection, acceleration/velocity calculation, and so on. On one tick it could take O(N*N) time, given that the optimisation will be done after the release of the app.

Should I be worried about this? Are Dalvik VMs considered the VMs with "moden GCs"? My app's code will get bloated after this point of development and I need to decide if I should at least wrap creation of Vectors around factory method so I could implement something like thread-local object pool on it later on.

Edit

  • The target API level is 21. So, the title is misleading. It's question about Android JVMs
2
  • wow, it's been awhile I learnt Android.
    – user292746
    Jan 30, 2018 at 2:51
  • FYI Dalvik VMs were mostly replaced by ART some time ago. Neither was/is a JVM. Feb 4, 2018 at 5:29

1 Answer 1

2

Probably don't start with object pooling: first make it work, then make it fast. You can always go back and optimize this code later.

Object pooling may not necessarily be a good optimization. It leads to a couple of tradeoffs:

  • Objects must be mutable so that they can be reinitialized. This may prevent automatic optimizations, and makes your code more difficult to reason about.

  • Pooling fights the GC, which makes the GC less efficient. With a GC, allocations can be super cheap (much cheaper than in C/C++). And the periodic cleanup is typically fast as well: most objects are short-lived, so they are likely already dead by the time GC looks at them. In contrast, pooled objects are basically immortal so they need extra care.

  • If an object is only used locally, it can sometimes be optimized away, as if the members were local variables. A precondition for this optimization is an escape analysis, that the object does not outlive the scope. Pooling prevents this.

  • In a non-GC'ed language, fixed-sized object pools have the advantage of avoiding memory fragmentation. That is not a consideration in Java, as objects can be moved.

So object pools are likely a complete antipattern for cheap, short-lived objects in a GC language. And a vector class is as simple as it gets. Instead of outsmarting your platform, cooperate with the runtime and write code that's easy to optimize. For example, using final classes simplifies optimization.

It is possible that at some point you may want to remove these classes, or at least reduce their use. When not optimized away, objects still have the disadvantage of a pointer indirection, and bad memory locality. An “object of arrays” approach can help (but shares some drawbacks with an object pool). It is also possible to manually inline the object contents, i.e. use float x1, x2, x3 instead of Vec x.

If it turns out that creation and cleanup of your vectors impacts performance measurably, then you can test those optimizations against the baseline of the currently working code. You can't do these tests as easily if you start with “optimized” code.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.