No more garbage : Pooling objects built with constructor functions

(for those unfamilliar with prototype and like, a more verbose version is available here )

Why creating an object creates an issue.

We all know about the evil garbage collector of Javascript, a cruel monster that might at any moment freeze your game to recollect unused memory, and waste some frames or loose some inputs events, spoiling the game experience.
The fight against garbage creation must be led on several fronts : I’ll adress here the specific case of object creation using a constructor function, and in this article, i’ll present a way to recycle those object in a simple manner.

For those who likes to know the end of the movie before it starts : The simple and classical pattern i expose here leads to X2 to X5 performance boost, and reduces game freeze.

You can find the code of this article here :

https://github.com/gamealchemist/Javascript-Pooling/tree/master/True_JS_Classes

Objects Built with a constructor function

Using  a constructor function looks like :

var MyClass = function (param1, param2, ...) {
    this.prop  = param1;
    this.prop2 = param2;
};

MyClass.prototype.method1 = function(..) { ... };

var myObject = new MyClass(param1, param2, ...);

For the creation of myObject, the memory system is used three times :

    1. using the new operator is equivalent, in Javascript, to create a new object : {}, and assigning it to the ‘this’ of the constructor function.
    2. The constructor function (MyClass) will then perform intialisation and add some properties to the object. Memory will again be allocated for those properties.
    3. When the object is no longer in use (‘goes out of scope’), its memory it is not recollected at once : rather it is marked for recollection, hence feeding the evil garbage collector. When, at some random point in time, memory is lacking, a large amount of memory is reclaimed all at once : garbage collection occurs, freezing the app for up to 10ms – a disaster-

Let’s go to the pool

There is a much neater way to handle your objects : use a pool.

A pool is a stack of object that you put aside for your app :

      • When a new object is required, just take it from the pool then initialize it.
      • When you no longer use your object, throw it back in the pool.
      • If you need an object and the pool is empty, then -too bad- just use standard new() to get a new one.

So allocations happens less frequently, and recollection might never happen :
If you determine the maximum number of objects your game might use, you can even pre-fill your pool with this number of objects, and you’ll never have to create or wait for recollection for this object.

How nice !

Javascript implementation.

Preliminary remark : I’ll make use here of ‘true’ Javascript ‘classes’,
i.e. classes :

      • setting properties in the constructor.
      • defining methods on the prototype.

This is the fastest and most memory efficient way to create objects in JS, and objects created this way also have the best performances.

To enable pooling, we need to have a function that will provide instances, set on the constructor function, and a dispose function, set on the pooled class’s prototype.

Rq : The pooled class constructor function MUST accept undefined arguments, since that’s what will get used when (pre)-filling the pool during the pool setup.
Rq2 : beware not to hold any reference to a pooled object after it’s been disposed. Since a disposed object will be later reused, you would then hold two references to the same object, creating bugs that might be hard to find.

So here is the code :


    // always take the latest version from gitHub, do not copy paste this code.

function setupPool(initialPoolSize) {
	if (!initialPoolSize || !isFinite(initialPoolSize)) throw('setupPool takes a size > 0 as argument.');
    this.pool                = []          ;
    this.poolSize            = 0           ;
    this.pnew                = pnew        ;
    Object.defineProperty(this.prototype, 'pdispose', { value : pdispose } ) ; 
    // pre-fill the pool.
    while (initialPoolSize-- >0) { (new this()).pdispose(); }
}

function  pnew () {
    var pnewObj  = null     ; 
    if (this.poolSize !== 0 ) {              
// the pool contains objects : grab one
           this.poolSize--  ;
           pnewObj = this.pool[this.poolSize];
           this.pool[this.poolSize] = null   ; 
    } else {
// the pool is empty : create new object
           pnewObj = new this() ;             
    }
    this.apply(pnewObj, arguments);           // initialize object
    return pnewObj;
}

function pdispose() {
    var thisCttr = this.constructor  ;
    if (this.dispose) this.dispose() ; // Call dispose if defined
    // throw the object back in the pool
    thisCttr.pool[thisCttr.poolSize++] = this ;   
}

Object.defineProperty(Function.prototype,'setupPool', { value : setupPool });

How to use ?

  // MyFunction is my constructor function
  MyFunction.setupPool(500) ;   // creates a pool with 500 objects

  // get a new instance
  var newInstance = MyFunction.pnew(arg1, arg2, ...);

  // make some use of newInstance...

  // then dispose of it
  newInstance.pdispose();

A few comments on this code :

      1. I use an always-growing array/stack, which length i handle separately in a poolSize property. this is to avoid garbage creation if the pool size increases.
      2. Think about the number of items your pool should initialy contain to avoid both waisting memory (too big) or waisting time (too littltt)
      3. I set, within the pool, to null the reference of the object we just grabbed to allow recollection in case it is not pdisposed afterwise, and just goes out of scope.
      4. In case you have some more disposal work to do when getting rid of an instance, just set a dispose() method on your object, that will call pdispose. One reason to do so might be that the object’s properties themselves are pooled.
      5. You might want to detect if you forget to pdispose some objects by counting all calls to pnew and to pdispose. At any moment you should have :
        activeObjectsCount == pnewCount  – (pdisposedCount – initialPoolSize)

Benchmarking

I built a test in JSPerf that reflects *somehow* the performance gain you can expect from pooling.

So i consider that we have 4 different pooled objects, with different memory footprint (more realistic), and a given number of active object that i select randomly within those 4 classes.
We’ll create/dispose of them using three methods :

      • standard way : using new / relying on garbage collection.
      • using an empty-at-first pool.
      • using an pre-filled pool.

You can see the test and experiment by yourself at http://jsperf.com/pooling-test/6

I took 100 active objects, and 50000 of them will be created/disposed randomly.

Here is a screenshot of the results for :
Win8 Chrome / mac OS FF / win 8 IE10 / ipad Safari / mac OS Safari :

pooled vs non-pooled performance

pooled vs non-pooled performance


We can see that :

pre-filling the pool helps either a little or not at all.
Chrome sees a near X2 boost.
Firefox manages poorly memory, bust can be as fast as Chrome if helped : X5 boost.
IE10 gets a X3.3 boost.
The ipad appreciates the pre-fill, and gets a X2 boost.
Safari on mac OS, also enjoys pre-fill X2 boost.

Let me know if you experiment pooling in your game : i especially think here of games using intensively vector computation, where the speed boost should be tremendous.

I hope you enjoyed reading this article, and i wish you a good game.

Advertisements
This entry was posted in Uncategorized. Bookmark the permalink.

6 Responses to No more garbage : Pooling objects built with constructor functions

  1. Jakub says:

    Great post! And performance boost is bigger than I was expecting:)

  2. billyninja says:

    great post indeed!

  3. Pingback: Let’s get those Javascript Arrays to work fast | gamealchemist

  4. Pingback: Object pooling in ImpactJS: Not as useful as I initially thought | Dave Voyles

  5. Pingback: Pooling with init : let’s throw ImpactJs classes in the pool. | gamealchemist

  6. Pingback: A better way of object pooling with impact.js (HTML5) | Dave Voyles

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s