5

I am currently writing a game for android where there are enemies that fly across the screen and then disappear, to be replaced by other enemies. Now, this happens very fast, and my code currently performs a lot of memory allocation and deallocation to create and delete these enemy objects, so I'm trying to find a way to optimize this. I got this Pool class implementation from a book on android game dev:

public class Pool<T> {
    public interface PoolObjectFactory<T> {
        public T createObject();
    }
    private final List<T>               freeObjects;
    private final PoolObjectFactory<T>  factory;
    private int                         maxObjects;

    public Pool(PoolObjectFactory<T> factory, int maxObjects) {
        this.maxObjects = maxObjects;
        this.factory = factory;
        freeObjects = new ArrayList<T>(maxObjects);
    }

    public T newObject() {
        T object = null;
        if (freeObjects.isEmpty()) {
            object = factory.createObject();
        } else {
            object = freeObjects.remove(freeObjects.size() - 1);
        }
        return object;
    }

    public void free(T object) {
        if (freeObjects.size() < maxObjects) freeObjects.add(object);
    }
}

Now, the way to use this class is as follows:

PoolObjectFactory<Enemy> factory = new  PoolObjectFactory<Enemy>() { 
    public Enemy createObject() { 
        return  new  Enemy(); 
    } 
}; 
Pool<Enemy> enemyPool = new  Pool<Enemy>(factory, 50); 

The obvious problem with this method is that you can't input any parameters to the createObject() method, thus forcing you to use classes that take no arguments in their constructor. This will force me to rewrite a lot of code since the Enemy class I'm using takes several different parameters. I can think of a couple of workarounds, like this one:

PoolObjectFactory<Enemy> factory = new  PoolObjectFactory<Enemy>() { 
    public Enemy createObject(Object... args) { 
        return  new  Enemy((Float)args[0], (Float)args[1]); 
    } 
}; 
Pool<Enemy> enemyPool = new  Pool<Enemy>(factory, 50); 

But it's error-prone and annoying to update. I could also initialize the Enemy object in the createObject() method with bogus values and then set them manually later, or I could create a Pool class for every single object but I would really prefer not doing that.

Any suggestions on how to improve this code? How do you fellow java game developers deal with pooling objects to avoid garbage collection? Thanks very much.

Lanaru
  • 9,421
  • 7
  • 38
  • 64

1 Answers1

1

1) You should override the createObject function in your PoolObjectFactory.

2) You will need a initialize() function that actually sets the parameters for each EnemyObject. Just have the constructor for the EnemyObject call the initialize function. Then, when you get the object out of the pool, you should just call initialize with your parameters and it should work perfectly.

you786
  • 3,659
  • 5
  • 48
  • 74
  • By overriding the createObject function, do you mean redefining it with different parameters? In that case, how would that be possible seeing as the signature of the method is defined in the interface? – Lanaru Jul 08 '12 at 20:59
  • I'm not disputing your suggestions at all - I'm just curious. Have you tested (or if you can point to some recent repeatable tests for my benefit) between using object pools on latest JVMs vs relying on JVM GC (Sun/OpenJDK on servers or Dalvik on mobile devices) to check for its impact on GC/application performance & responsiveness. Once again, just looking for information - thanks. – ali haider Jul 08 '12 at 21:01
  • No, I have not tested it yet. I have been noticing some lag in my application and thought that this might be the cause of the problem (I know it's bad practice to guess before testing, but I was planning on using object pooling anyway). This is actually my first android game so I'm still working some kinks out, but once I get the pool working I'll try to run a few tests (if I can find a good tutorial on how to do so). – Lanaru Jul 08 '12 at 21:17
  • @alihaider No problem. Having developed an Android game, there are definitely noticeable pauses when the GC runs. It's not about the object allocation, which is basically negligible nowadays from what I understand. Although I don't have any definite tests/statistics, it does seem to be a recommended practice in games with high object allocation counts. – you786 Jul 08 '12 at 21:18
  • You786, could you please explain your point 1)? (See my first comment) – Lanaru Jul 08 '12 at 21:21
  • 1
    @alihaider http://www.devahead.com/blog/2011/12/coding-for-performance-and-avoiding-garbage-collection-in-android/ – you786 Jul 08 '12 at 21:22
  • @Lanaru You should be able to override the method if PoolObjectFactory is not an abstract class. – you786 Jul 08 '12 at 21:41