Pool – A generic utility class for minimizing GC in your games

The basic idea is straight forward, it allows you to pre-create a Pool of whatever game object you like and reuse them instead of relying on creating new objects and GCing them. It’s useful for Desktop games of course, but it was intended to help specifically with Android dev.

Since these classes are not in the latest release, I thought I’d post them here with some basic usage:

Pool.java
[java]
package tonegod.gui.framework.core.util;

import com.jme3.util.SafeArrayList;

/**
*

  • @author t0neg0d
    */
    public class Pool<T> {
    SafeArrayList<PoolResource<T>> pool = new SafeArrayList(PoolResource.class);
    PoolObjectFactory<T> factory;

    /**

    • Creates a Pool of initial capacity initSize using the PoolObjectFactory provided by the user.
    • @param factory The PoolObjectFactory used to create new instances of the T
    • @param initSize The initial size of the Pool
      */
      public Pool(PoolObjectFactory<T> factory, int initSize) {
      this.factory = factory;
      for (int i = 0; i < initSize; i++) {
      pool.add(new PoolResource<T>(factory.newPoolObject()));
      }
      }

    /**

    • Returns the next available T resource from the pool. If no resource is available, the Pool size is increased by 1 and the new instance is returned.
    • NOTE: It is important that any resource retrieved from this method is passed to @freePoolObject when no longer in use.
    • @return An instance of T from the Pool that is currently not in use by the application.
      */
      public T getNextAvailable() {
      T ret = null;
      for (PoolResource<T> resource : pool.getArray()) {
      if (!resource.getInUse()) {
      ret = resource.getResource();
      resource.setInUse(true);
      break;
      }
      }
      if (ret == null) {
      PoolResource<T> next = new PoolResource<T>(factory.newPoolObject());
      ret = next.getResource();
      next.setInUse(true);
      pool.add(next);
      }
      return ret;
      }

    /**

    • Frees the resource for reuse.
    • @param poolObject The resource originally returned by @getNextAvailable
    • @return Boolean representing if the resource was successfully freed.
      */
      public boolean freePoolObject(T poolObject) {
      boolean ret = false;
      for (PoolResource<T> resource : pool.getArray()) {
      if (resource.getResource() == poolObject) {
      resource.setInUse(false);
      ret = true;
      break;
      }
      }
      return ret;
      }

    private class PoolResource<T> {
    T resource;
    private boolean inUse = false;

     public PoolResource(T resource) {
     	this.resource = resource;
     }
     
     public T getResource() { return this.resource; }
     
     public void setInUse(boolean inUse) { this.inUse = inUse; }
     
     public boolean getInUse() { return this.inUse; }
    

    }
    }
    [/java]

PoolObjectFactory.java
[java]
package tonegod.gui.framework.core.util;

/**
*

  • @author t0neg0d
    */
    public interface PoolObjectFactory<T> {
    public T newPoolObject();
    }
    [/java]

And now for the usage. First, you create a PoolObjectFactory class… like so:

[java]
/*

  • To change this template, choose Tools | Templates
  • and open the template in the editor.
    */
    package bugs;

import bugs.enemies.EnemyPawn;
import bugs.enemies.EnemyShip;
import tonegod.gui.framework.core.util.PoolObjectFactory;

/**
*

  • @author t0neg0d
    */
    public class EnemyFactory implements PoolObjectFactory<EnemyShip> {
    Main main;

    public EnemyFactory(Main main) {
    this.main = main;
    }

    public EnemyShip newPoolObject() {
    // Here is where you add you constructor for new instances of the game object to store in the Pool you will create next
    return new EnemyPawn(main);
    }
    }
    [/java]

And finally… Somewhere in your initialization code:

[java]
Pool<EnemyShip> enemies;
EnemyFactory factory;

@Override
public void simpleInitApp() {
	enemies = new Pool&lt;EnemyShip&gt;(new EnemyFactory(this), 60);
	
	// At this point anytime you need an EnemyShip, you call:
	EnemyShip e1 = enemies.getNextAvailable();
	
	// Make any instance specific alteration needed for this use and go...
	
	// And when you are done with it:
	enemies.freePoolObject(e1);
}

[/java]

/wave

4 Likes

Heh… still obviously needs a bit of cleanup.

The constructor should be passing in PoolObjectFactory as:

[java]
PoolObjectFactory<T> factory;

public Pool(PoolObjectFactory<T> factory, int initSize)

[/java]

And all casting should be removed;

[java]
for (int i…

// should be

for (T resource : pool)
[/java]

and any pool.get should be replaced with resource above.

EDIT: Ignore this… it has been updated above.

Just some notes:

  1. Things like for (T resource : pool)
    …will create an Iterator object every time. Not great if you purport to be cutting down on garbage (which isn’t really a problem on desktop but is on Android)
    JME’s SafeArrayList was written to get around this issue by providing direct access to the array. It’s GC characteristics in the face of modifications are a little different, though, since it will recreate the array if an underlying list has changed.

  2. Small thing but since you don’t initialize the capacity of your array lists the internal arrays will end up being larger than needed. Of course, after initSize that will happen anyway and is relatively small. But after the constructor, the internal array is larger than needed. Probably not really something to worry about.

ArrayList is pretty GC-friendly otherwise. adds and removes do so without internal iterators, so there is that. With an internal element data structure you could do away with the inUse.add/removes and the separate lists. SafeArrayList would be a more attractive implementation then because the internal array would only be invalidated when the pool size was exceeded.

You might also consider adding a max capacity to catch cases where resources aren’t being returned to the pool.

1 Like
@pspeed said: Just some notes: 1) Things like for (T resource : pool) ...will create an Iterator object every time. Not great if you purport to be cutting down on garbage (which isn't really a problem on desktop but is on Android) JME's SafeArrayList was written to get around this issue by providing direct access to the array. It's GC characteristics in the face of modifications are a little different, though, since it will recreate the array if an underlying list has changed.
  1. Small thing but since you don’t initialize the capacity of your array lists the internal arrays will end up being larger than needed. Of course, after initSize that will happen anyway and is relatively small. But after the constructor, the internal array is larger than needed. Probably not really something to worry about.

ArrayList is pretty GC-friendly otherwise. adds and removes do so without internal iterators, so there is that. With an internal element data structure you could do away with the inUse.add/removes and the separate lists. SafeArrayList would be a more attractive implementation then because the internal array would only be invalidated when the pool size was exceeded.

You might also consider adding a max capacity to catch cases where resources aren’t being returned to the pool.

I’ll update this to reflect the suggested changes. I was hoping to get input from someone who could point just these sorts of things. Even in its current form, there is significant improvement the longer a game runs. I’d be thrilled if this worked better!

Ah… actually. Internal data structure is a muuuuuch better idea. my original idea was invasive, so I opt’d for this instead. Not sure why I didn’t consider that as an option in the first place. Really glad you looked at this.

I may have a question or three concerning the SafeArrayList, as I tried leveraging it a LOOOOONG time ago with no success. However, this was my lack of understanding at the time I am sure. Hopefully that has changed significantly!

It’s worth mentioning Apache Commons Pool as a possible alternative.

@thetoucher said: It's worth mentioning Apache Commons Pool as a possible alternative.

I almost mentioned it, too, but even the basic generic pool is still heavily thread safe internally.

@thetoucher said: It's worth mentioning Apache Commons Pool as a possible alternative.

It was hard to choose between:

Version 1

and:

Version 2 - the complete rewrite (not sure what this means… but it freaked me out)

EDIT: Meaning… even with the “much room for improvement”… it still won’t require a “complete rewrite”. Um… actually… seriously… WTH does that mean??

@pspeed
So, after looking through SafeArrayList, am I correct in assuming that once the backingArray is created, as long as it is not altered, all is good? Does this include using listIterator() or should I always use getArray()?

@t0neg0d said: @pspeed So, after looking through SafeArrayList, am I correct in assuming that once the backingArray is created, as long as it is not altered, all is good? Does this include using listIterator() or should I always use getArray()?

SafeArrayList has some interesting characteristics that make it useful in many situations:

  1. It is safe to add or remove items while iterating. This is nice when iterating over listeners or controls, etc. where the listener or control may remove itself or add other listeners.
  2. (and the important one in your case), you can avoid creating Iterator() objects if you use the backingArray directly. If you call any of the regular iterator methods then you are going to create an Iterator object, of course.

The backing array stays constant as long as no items are added or removed from the list. If you modify the list then the backing array will be recalculated the next time it is requested.

The only downside is that storage is effectively doubled… but in your original implementation it was effectively doubled anyway. If you switch to a single SafeArrayList of PoolEntry elements (where the pool has an inUse flag or somesuch) then you are no worse off than before, re: storage… but will save time manipulating the order of the list. Keep a count of the available objects versus pool capacity and you will know easily whether to search for a blank slot or add to the end of the pool.

Note: “searching for a blank slot” sounds bad but your old approach was also doing an indexOf search during removal from inUse so it’s probably a wash… moreover, there were lots of System.arraycopy() ops going on that are avoided in the proposed approach.

1 Like

@pspeed
Ok… I think I have this correct. If you get a chance would you look over the Pool class above and make sure that I’m making the best use of SafeArrayList?

Anything you see that should be handled differently… just point out.

Also, using the internal class for flagging resources as inUse added a search + Object comparison to the freePoolObject method. Is there any way around this? Or should this be ok?

@t0neg0d said: @pspeed Ok... I think I have this correct. If you get a chance would you look over the Pool class above and make sure that I'm making the best use of SafeArrayList?

Anything you see that should be handled differently… just point out.

Also, using the internal class for flagging resources as inUse added a search + Object comparison to the freePoolObject method. Is there any way around this? Or should this be ok?

Since the old version has gone away, I can’t confirm but I remember that was calling inUse.remove(object)? Which was iterating over the array elements to find the object.

I don’t think you’ve lost anything.

This:
for (int i = 0; i < pool.size(); i++) {
pool.get(i)

Is not really how SafeArrayList was meant to be used. You call extra methods every loop iteration.
for( PoolResource r : pool.getArray() )
…is Iterator free and will operate directly on the array instead of making the get() and size() calls.

1 Like
@pspeed said: Since the old version has gone away, I can't confirm but I remember that was calling inUse.remove(object)? Which was iterating over the array elements to find the object.

I don’t think you’ve lost anything.

This:
for (int i = 0; i < pool.size(); i++) {
pool.get(i)

Is not really how SafeArrayList was meant to be used. You call extra methods every loop iteration.
for( PoolResource<T> r : pool.getArray() )
…is Iterator free and will operate directly on the array instead of making the get() and size() calls.

Awesome… thats the part I was unsure of. I’ll update that! Thanks a ton for helping me understand how to best implement this.

I would recommend to also specificyl say if the class is threadsafe or not in the javadoc, as this can often lead to hard to debug errors.

@Empire Phoenix said: I would recommend to also specificyl say if the class is threadsafe or not in the javadoc, as this can often lead to hard to debug errors.

Before adding this to the build, I’ll have had a chance to verify… but I believe it should be now with the switch to SafeArrayList.

EDIT: Actually… the getNext method may need to be synchronized. I’ll play around with it and find out!

http://hub.jmonkeyengine.org/javadoc/com/jme3/util/SafeArrayList.html

I’m not sure, I would say its not threadsave. "except that it is not concurrent "

Wich would make sense, cause a synchronisation in such a basic class would really slow the jmerenderer down.
I would even say that making/keeping this threadunsafe is probably a good idea, as a sychnronizing is a heavy operation.
It should just be documented, to ease everyones live.

@Empire Phoenix said: http://hub.jmonkeyengine.org/javadoc/com/jme3/util/SafeArrayList.html

I’m not sure, I would say its not threadsave. "except that it is not concurrent "

Wich would make sense, cause a synchronisation in such a basic class would really slow the jmerenderer down.
I would even say that making/keeping this threadunsafe is probably a good idea, as a sychnronizing is a heavy operation.

True… I guess one could always use Futures and enqueue calls if it become critical to use with multi-threading.

It is currently not thread safe. SafeArrayList is not meant to be thread safe.

If you want thread safety then you should use the Apache Commons pool implementation already linked. (pool2)… because it’s only down side is the thread safety overhead.

Since much of JME already works on a “be careful of your threads” policy, I assumed you were trying to make a fast-but-not-thread-safe alternative. If not then just use the already built one.

@pspeed said: Since much of JME already works on a "be careful of your threads" policy, I assumed you were trying to make a fast-but-not-thread-safe alternative. If not then just use the already built one.

This was the original intent.

The pool class looks solid. It should be handy for quite a few people.

I had never twigged that iterating over an array doesn’t create an iterator (although with hindsight it’s obvious) - another useful snippet picked up from these forums :slight_smile:

@zarch said: The pool class looks solid. It should be handy for quite a few people.

I had never twigged that iterating over an array doesn’t create an iterator (although with hindsight it’s obvious) - another useful snippet picked up from these forums :slight_smile:

You and me both… thanks for reviewing this btw