Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Temporary Iterators are slowing my Android Game

This question involves memory management in Java for performance reasons: because I am developing this program as an Android Game and memory GC's kill my performance. So I have done a large amount of work so far and it turns out that I am doing a great job of optimizing the memory usage of my game, but I have one problem: iterators!

Here is what I am doing:

  1. Start game level.
  2. Start allocation tracker (this way we ignore all of the allocations that will remain for as long as the level runs; I have many objects that only get created once at the beginning of the level and they are not the problem).
  3. Do a few things in the level and get the allocations.

My allocations are full of this:

466 24 java.util.AbstractList$SimpleListIterator 12 java.util.AbstractList iterator
465 24 java.util.AbstractList$SimpleListIterator 12 java.util.AbstractList iterator
464 24 java.util.AbstractList$SimpleListIterator 12 java.util.AbstractList iterator
463 24 java.util.AbstractList$SimpleListIterator 12 java.util.AbstractList iterator
461 24 java.util.AbstractList$SimpleListIterator 12 java.util.AbstractList iterator
456 24 java.util.ArrayList$ArrayListIterator 12 java.util.ArrayList iterator
454 24 java.util.ArrayList$ArrayListIterator 12 java.util.ArrayList iterator
453 24 java.util.ArrayList$ArrayListIterator 12 java.util.ArrayList iterator
452 24 java.util.ArrayList$ArrayListIterator 12 java.util.ArrayList iterator

So the only objects that are being allocated while my game is running are iterators! Okay, well now to fix it then...what code is causing the problem I asked...here it is:

for (Segment side : listOfSides.getSides()) {
    // do stuff
}

Yes, it turns out that for-each syntax calls iterator behind the scenes to populate each element. Which makes perfect sense and exactly what I expected it to do but I did not realise that it could build up so horribly and cause a performance problem for games. If I could get rid of this problem then it would really make my game run like lightning no matter what phone it was on. So my question is: what would you do to make it so that all of these temporary iterators were not created and then immediately discarded resulting in nasty GC runs? Bonus points for doing so in a way that does not make my code completely ugly! (And using ndk on Android is not an option)

P.S. I was thinking that for all of my ArrayLists I could start using the get(int i) function as they are arrays behind the scenes and the integer I would use to index that would be placed on the stack and not the heap. But for the other objects like a HashMap and LinkedList I am not sure what to do.

like image 292
Robert Massaioli Avatar asked Jul 15 '12 07:07

Robert Massaioli


People also ask

Is for each better than for?

If the extra hidden variable is enregistered, but the parameter itself is not during code generation, then the for-each would be faster; if the parameter is enregistered in the for(;;) example, execution time would be identical.

Which is faster for or foreach Java?

Foreach performance is approximately 6 times slower than FOR / FOREACH performance. The FOR loop without length caching works 3 times slower on lists, comparing to arrays. The FOR loop with length caching works 2 times slower on lists, comparing to arrays.

Can iterators be reused?

iterators are not reusable; you need to get a fresh Iterator from the Iterable collection each time you want to iterate over the elements.


1 Answers

ArrayList and LinkedList let you traverse the elements using get(int i) (note it might be slow for LinkedList, I don't know how get() is implemented.) This is the recommended approach to avoid allocating iterators. If you look at the source code of the platform you will notice that we try to avoid using the for-each syntax as much as possible.

For HashMap you can grab the underlying sets using entrySet() and then call toArray(Object[]) and pass a pre-allocated array big enough to hold all the values. Alternatively, see if you could use the various SparseArray classes offered by Android.

like image 121
Romain Guy Avatar answered Sep 27 '22 21:09

Romain Guy