Performance tips for Android

From JPCT
Revision as of 18:20, 16 December 2014 by Admin (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Performance tips for Android

These are general tips and true for all Android applications, not just for jPCT-AE. It's a collection of things, that i found out to be most important during the development of AE. Remember that this is targeted to real time apps like games. If you are not doing this, your mileage may vary.

If you are used to the best pratices of the desktop Java world and praise OO and the mightly VM at least twice a day, the following tips can be very disturbing for you. You have been warned...

The order is roughly from common to exotic...


Avoid object creations

If possible, create your objects before starting the actual game. Or at least try to reuse old objects. Object creation is expensive on Android. Try to pool objects if possible. jPCT-AE offers some help for this. Many methods that return a Matrix or a SimpleVector exist in two flavours now: One that simply returns a new instance and one that takes an instance as an argument and fills and returns that one. You can save the creation of unneeded, short lived objects with that.

Avoid object destruction

If an object isn't referenced any longer, it is free to be garbage collected. This is actually a good thing as it frees some memory. However, on Android garbage collection is very slow. You can spend 100-200ms on one run and free 10bytes at the end. So if possible, reuse objects and use object pools to avoid too many objects being garbage collected in your game's main loop. You and your players will notice a 100ms lag! jPCT-AE is already optimized to create/destroy as few objects as possible for the most parts.


Watch the garbage collection

As said, it can be dog slow, especially on older versions of Android. It might be a good idea to place some finalize()/gc() calls after doing your setup work and before starting the actual game. jPCT-AE offers some help for this in the util-package in the form of the MemoryHelper.

Avoid getters and setters

If possible, make your attributes public or package public. Don't use getters or setters, i.e. instead of

blah.setBlubb(gark.getBlubb());

do

blah.blubb=gark.blubb;

Avoid method calls

For simple methods that you call very often in a loop, consider to inline the code. The VM doesn't do this for you and method calls are quite expensive.

Avoid collections

If possible, use arrays instead. Preferable those of native types like int[], long[], float[]...not object arrays. Watch out for auto-boxing/-unboxing.


Silence the touch events

On older versions of Android, touch events can flood the system by creating events as if there was no tomorrow. Consider to add a Thread.sleep() in your onTouchEvent()-method. Play around with a value of 10-20. It should help to greatly decrease touch events (evil objects being created and disposed). Be careful that you don't sleep too long or your movement will get choppy.

However, touch controls suck anyway on older versions of Android, because of this bug!

Avoid interfaces

Write classes, not interfaces. This is an Android application, most likely a game...you'll start from scratch anyway on your next project. You don't need this interface that allows for swapping implementations if needed. You are not going to do this anyway, it just costs you performance.

Avoid extended for-loops

They can create quite a lot of garbage behind your back. So instead of

for (Object o:os) {
...
}

do

int end=os.size();
for (int i=0; i<end; i++) {
   Object o=os.get(i);
...
}

Dereference if possible

Don't do this:

for (int i=0; i<gark.blubb.length; i++) {
   if (gark.blubb[i]>10) {
      a=gark.blubb[i];
      ...
   } else {
     a=gark.blubb[i]+123;
     ... 
   }
   b=gark.blubb[i]+12;
   ... 
}

Do this:

int[] garkBlubb=gark.blubb;
int end=garkBlubb.length;
for (int i=0; i<end; i++) {
   int t=garkBlubb[i];
   if (t>10) {
      a=t;
      ...
   } else {
     a=t+123;
     ... 
   }
   b=t+12;
   ... 
}


Avoid float or double

Just try to avoid them. If you can't, use Android's FloatMath instead of Math. If you have to divide multiple times by the same value, consider to multiply with 1f/value instead.

Warning: Strange optimization ahead...if you have to compare many floats multiple times, consider to compare their int representation instead, i.e. use Float.floatToIntBits(<float>). Depending on your application and your hardware, this might by faster by a factor of 2-3.


Avoid single puts into native memory

Try to backup your native data by an array in the VM's memory. If that's too costly (memory wise), use at least a small buffer to buffer puts. It's usually cheaper to fill that buffer first and put that in one call instead of doing single puts.


Don't go crazy on optimizing things

Use caution when optimizing...maybe your optimization is only that fast, because it does different things than the orginal version. Double check that your optimized code is still correct. Only optimize the critical sections. It makes no sense to dereference everything in a setup method.


Don't play around with thread priorities

...just don't. It's no good.