Keep Your Flash Project’s Memory Usage Stable With Object Pooling

Keep Your Flash Project’s Memory Usage Stable With Object Pooling

Tutorial Details
  • Difficulty: Beginner
  • Platform: Flash/AIR
  • Language: AS3
  • Software used: FlashDevelop 4
  • Estimated Completion Time: 30 minutes

Memory usage is an aspect of development that you really have to be careful about, or it might end up slowing down your app, taking up a lot of memory or even crashing everything. This tutorial will help you to avoid those bad potential outcomes!


Final Result Preview

Let’s take a look at the final result we will be working towards:

Click anywhere on the stage to create a firework effect, and keep an eye on the memory profiler in the top-left corner.


Step 1: Introduction

If you have ever profiled your application using any profiling tool or used any code or library that tells you the current memory usage of your application, you may have noticed that many times the memory usage goes up, and then goes down again (if you haven’t, your code is superb!). Well, although these spikes caused by big memory usage look kinda cool, it’s not good news for either your application or (consequently) your users. Keep reading to understand why this happens and how to avoid it.


Step 2: Good and Bad Usage

The image below is a really great example of poor memory management. It’s from a prototype of a game. You must notice two important things: the big spikes on memory usage and the memory usage peak. The peak is almost at 540Mb! That means this prototype alone reached the point of using 540Mb of the user’s computer RAM – and that is something you definitely want to avoid.

Bad memory usage

This problem begins when you start creating a lot of object instances in your application. Unused instances will keep using your application’s memory until the garbage collector runs, when they get deallocated – causing the big spikes. An even worse situation happens when the instances simply won’t get deallocated, causing your application’s memory usage to keep growing until something crashes or breaks. If you want to know more about the latter problem and how to avoid it, read this Quick Tip about garbage collection.

In this tutorial we will not address any garbage collector issues. We’ll instead work on building structures that efficiently keep objects in the memory, making its usage completely stable and thus keeping the garbage collector from cleaning up memory, making the application faster. Take a look at the memory usage of the same prototype above, but this time optimized with the techniques shown here:

Good memory usage

All this improvement can be achieved using object pooling. Read on to understand what it is and how it works.


Step 3: Types of Pools

Object pooling is a technique wherein a pre-defined number of objects are created when the application is initialized, and kept in the memory during the entire application lifetime. The object pool gives objects when the application requests them, and resets the objects back to the initial state when the application is finished using them. There are many types of object pools, but we will only take a look at two of them: the static and the dynamic object pools.

The static object pool creates a defined number of objects and only keeps that amount of objects during the entire application life time. If an object is requested but the pool has already given all its objects, the pool returns null. When using this kind of pool, it is necessary to address issues such as requesting an object and getting nothing back.

The dynamic object pool also creates a defined number of objects on initialization, but when an object is requested and the pool is empty, the pool creates another instance automatically and returns that object, increasing the pool size and adding the new object to it.

In this tutorial we will build a simple application that generates particles when the user clicks on the screen. These particles will have a finite lifetime, and then will be removed from the screen and returned to the pool. In order to do that, we will first create this application without object pooling and check the memory usage, and then implement the object pool and compare the memory usage to before.


Step 4: Initial Application

Open FlashDevelop (see this guide) and create a new AS3 project. We will use a simple small colored square as the particle image, which will be drawn with code and will move according to a random angle. Create a new class called Particle that extends Sprite. I’ll assume that you can handle the creation of a particle, and just highlight the aspects that will keep track of the particle’s lifetime and removal from screen. You can grab the full source code of this tutorial on the top of the page if you’re having trouble creating the particle.

private var _lifeTime:int;

public function update(timePassed:uint):void
{
	// Making the particle move
	x += Math.cos(_angle) * _speed * timePassed / 1000;
	y += Math.sin(_angle) * _speed * timePassed / 1000;
	
	// Small easing to make movement look pretty
	_speed -= 120 * timePassed / 1000;
	
	// Taking care of lifetime and removal
	_lifeTime -= timePassed;
	
	if (_lifeTime <= 0)
	{
		parent.removeChild(this);
	}
}

The code above is the code responsible for the particle’s removal from the screen. We create a variable called _lifeTime to contain the number of miliseconds that the particle will be on the screen. We initialize by default its value to 1000 on the constructor. The update() function is called every frame and receives the amount of miliseconds that passed between frames, so that it can decrease the particle’s lifetime value. When this value reaches 0 or less, the particle automatically asks its parent to remove it from the screen. The rest of the code takes care of the particle’s movement.

Now we’ll make a bunch of these be created when a mouse click is detected. Go to Main.as:

private var _oldTime:uint;
private var _elapsed:uint;

private function init(e:Event = null):void 
{
	removeEventListener(Event.ADDED_TO_STAGE, init);
	// entry point
	stage.addEventListener(MouseEvent.CLICK, createParticles);
	addEventListener(Event.ENTER_FRAME, updateParticles);
	
	_oldTime = getTimer();
}

private function updateParticles(e:Event):void 
{
	_elapsed = getTimer() - _oldTime;
	_oldTime += _elapsed;
	
	for (var i:int = 0; i < numChildren; i++)
	{
		if (getChildAt(i) is Particle)
		{
			Particle(getChildAt(i)).update(_elapsed);
		}
	}
}

private function createParticles(e:MouseEvent):void 
{
	for (var i:int = 0; i < 10; i++)
	{
		addChild(new Particle(stage.mouseX, stage.mouseY));
	}
}

The code for updating the particles should be familiar to you: it’s the roots of a simple time-based loop, commonly used in games. Don’t forget the import statements:

import flash.events.Event;
import flash.events.MouseEvent;
import flash.utils.getTimer;

You can now test your application and profile it using FlashDevelop’s built-in profiler. Click a bunch of times on the screen. Here’s what my memory usage looked like:

Unhandled memory usage

I clicked until the garbage collector started to run. The application created over 2000 particles that were collected. Is it starting to look like the memory usage of that prototype? It looks like it, and this is definitely not good. To make profiling easier, we’ll add the utility that was mentioned in the first step. Here’s the code to add in Main.as:

private function init(e:Event = null):void 
{
	removeEventListener(Event.ADDED_TO_STAGE, init);
	// entry point
	stage.addEventListener(MouseEvent.CLICK, createParticles);
	addEventListener(Event.ENTER_FRAME, updateParticles);
	
	addChild(new Stats());
	
	_oldTime = getTimer();
}

Don’t forget to import net.hires.debug.Stats and it’s ready to be used!


Step 5: Defining a Poolable Object

The application we built in Step 4 was pretty simple. It featured only a simple particle effect, but created a lot of trouble in the memory. In this step, we will begin working on an object pool in order to fix that problem.

Our first step towards a good solution is to think about how the objects can be pooled without problems. In an object pool, we need to always make sure that the object created is ready for use and that the object returned is completely “isolated” from the rest of the application (i.e. holds no references to other things). In order to force each pooled object to be able to do that, we are going to create an interface. This interface will define two important functions that the object must have: renew() and destroy(). That way, we can always call those methods without worrying about whether or not the object has them (because it will have). This also means that every object we want to pool will need to implement this interface. So here it is:

package  
{
	public interface IPoolable 
	{
		function get destroyed():Boolean;
		
		function renew():void;
		function destroy():void;
	}
}

Since our particles will be poolable, we need to make them implement IPoolable. Basically we move all the code from their constructors to the renew() function, and eliminate any external references to the object in the destroy() function. Here’s what it should look like:

/* INTERFACE IPoolable */

public function get destroyed():Boolean 
{
	return _destroyed;
}

public function renew():void 
{
	if (!_destroyed)
	{
		return;
	}
	
	_destroyed = false;
	
	graphics.beginFill(uint(Math.random() * 0xFFFFFF), 0.5 + (Math.random() * 0.5));
	graphics.drawRect( -1.5, -1.5, 3, 3);
	graphics.endFill();
	
	_angle = Math.random() * Math.PI * 2;
	
	_speed = 150; // Pixels per second
	
	_lifeTime = 1000; // Miliseconds
}

public function destroy():void 
{
	if (_destroyed)
	{
		return;
	}
	
	_destroyed = true;
	
	graphics.clear();
}

The constructor also shouldn’t require any arguments any more. If you want to pass any information to the object, you’ll have to do it through functions now. Due to the way that the renew() function works now, we also need to set _destroyed to true in the constructor so that the function can be run.

With that, we have just adapted our Particle class to behave as an IPoolable. That way, the object pool will be able to create a pool of particles.


Step 6: Starting the Object Pool

It is time now to create a flexible object pool which can pool any object we want. This pool will act a bit like a factory: instead of using the new keyword to create objects you can use, we will instead call a method in the pool that returns to us an object.

For the purposes of simplicity, the object pool will be a Singleton. That way we can access it anywhere within our code. Start by creating a new class called “ObjectPool” and adding the code to make it a Singleton:

package  
{
	public class ObjectPool 
	{
		private static var _instance:ObjectPool;
		private static var _allowInstantiation:Boolean;
		
		public static function get instance():ObjectPool
		{
			if (!_instance)
			{
				_allowInstantiation = true;
				_instance = new ObjectPool();
				_allowInstantiation = false;
			}
			
			return _instance;
		}
		
		public function ObjectPool() 
		{
			if (!_allowInstantiation)
			{
				throw new Error("Trying to instantiate a Singleton!");
			}
		}
		
	}

}

The variable _allowInstantiation is the core of this Singleton implementation: it’s private, so only the own class can modify, and the only place where it should be modified is before creating the first instance of it.

We must now decide how to hold the pools inside this class. Since it will be global (i.e. can pool any object in your application), we need to first come up with a way to always have an unique name for each pool. How to do that? There are many ways, but the best I’ve found so far is to use the objects’ own class names as the pool name. That way, we could have a “Particle” pool, a “Enemy” pool and so on… but there’s another problem. Class names only have to be unique within their packages, so for instance a class “BaseObject” within the “enemies” package and a class “BaseObject” within the “structures” package would be allowed. That would cause problems in the pool.

The idea of using class names as identifiers for the pools is still great, and this is where flash.utils.getQualifiedClassName() comes to help us. Basically this function generates a string with the full class name, including any packages. So now, we can use each object’s qualified class name as the identifier for their respective pools! This is what we will add in the next step.


Step 7: Creating Pools

Now that we have a way to identify pools, it’s time to add the code that creates them. Our object pool should be flexible enough to support both static and dynamic pools (we talked about these in Step 3, remember?). We also need to be able to store the size of each pool and how many active objects there are in each one. A good solution for that is to create a private class with all this information and store all pools within an Object:

package  
{
	public class ObjectPool 
	{
		private static var _instance:ObjectPool;
		private static var _allowInstantiation:Boolean;
		
		private var _pools:Object;
		
		public static function get instance():ObjectPool
		{
			if (!_instance)
			{
				_allowInstantiation = true;
				_instance = new ObjectPool();
				_allowInstantiation = false;
			}
			
			return _instance;
		}
		
		public function ObjectPool() 
		{
			if (!_allowInstantiation)
			{
				throw new Error("Trying to instantiate a Singleton!");
			}
			
			_pools = {};
		}
		
	}

}

class PoolInfo
{
	public var items:Vector.<IPoolable>;
	public var itemClass:Class;
	public var size:uint;
	public var active:uint;
	public var isDynamic:Boolean;
	
	public function PoolInfo(itemClass:Class, size:uint, isDynamic:Boolean = true)
	{
		this.itemClass = itemClass;
		items = new Vector.<IPoolable>(size, !isDynamic);
		this.size = size;
		this.isDynamic = isDynamic;
		active = 0;
		
		initialize();
	}
	
	private function initialize():void
	{
		for (var i:int = 0; i < size; i++)
		{
			items[i] = new itemClass();
		}
	}
}

The code above creates the private class which will contain all the information about a pool. We also created the _pools object to hold all object pools. Below we will create the function that registers a pool in the class:

public function registerPool(objectClass:Class, size:uint = 1, isDynamic:Boolean = true):void
{
	if (!(describeType(objectClass).factory.implementsInterface.(@type == "IPoolable").length() > 0))
	{
		throw new Error("Can't pool something that doesn't implement IPoolable!");
		return;
	}
	
	var qualifiedName:String = getQualifiedClassName(objectClass);
	
	if (!_pools[qualifiedName])
	{
		_pools[qualifiedName] = new PoolInfo(objectClass, size, isDynamic);
	}
}

This code looks a bit trickier, but don’t panic. It’s all explained here. The first if statement looks really weird. You may have never seen those functions before, so here’s what it does:

  • The describeType() function creates a XML containing all the information about the object we passed it.
  • In the case of a class, everything about it is contained within the factory tag.
  • Inside that, the XML describes all the interfaces that the class implements with the implementsInterface tag.
  • We do a quick search to see if the IPoolable interface is among them. If so, then we know we can add that class to the pool, because we will be able to successfully cast it as an IObject.

The code after this check just creates an entry within _pools if one didn’t already exist. After that, the PoolInfo constructor calls the initialize() function within that class, effectively creating the pool with the size we want. It’s now ready to be used!


Step 8: Getting an Object

In the last step we were able to create the function that registers an object pool, but now we need to get an object in order to use it. It’s very straightforward: we get an object if the pool isn’t empty and return it. If the pool is empty, we check whether it’s dynamic; if so, we increase its size, and then create a new object and return it. If not, we return null. (You can also choose to throw an error, but it’s better to just return null and make your code work around this situation when it happens.)

Here’s the getObj() function:

public function getObj(objectClass:Class):IPoolable
{
	var qualifiedName:String = getQualifiedClassName(objectClass);
	
	if (!_pools[qualifiedName])
	{
		throw new Error("Can't get an object from a pool that hasn't been registered!");
		return;
	}
	
	var returnObj:IPoolable;
	
	if (PoolInfo(_pools[qualifiedName]).active == PoolInfo(_pools[qualifiedName]).size)
	{
		if (PoolInfo(_pools[qualifiedName]).isDynamic)
		{
			returnObj = new objectClass();
			
			PoolInfo(_pools[qualifiedName]).size++;
			PoolInfo(_pools[qualifiedName]).items.push(returnObj);
		}
		else
		{
			return null;
		}
	}
	else
	{
		returnObj = PoolInfo(_pools[qualifiedName]).items[PoolInfo(_pools[qualifiedName]).active];
		
		returnObj.renew();
	}
	
	PoolInfo(_pools[qualifiedName]).active++;
	
	return returnObj;
}

In the function, first we check that the pool actually exists. Assuming that condition is met, we check whether the pool is empty: if it is but it is dynamic, we create a new object and add into the pool. If the pool isn’t dynamic, we stop the code there and just return null. If the pool still has an object, we get the object closest to the beginning of the pool and call renew() on it. This is important: the reason we call renew() on an object that was already in the pool is to guarantee that this object will be given at a “usable” state.

You are probably wondering: why don’t you also use that cool check with describeType() in this function? Well, the answer is simple: describeType() creates an XML every time we call it, so it’s very important to avoid the creation of objects that use a lot of memory and that we can’t control. Besides, only checking to see whether the pool really exists is enough: if the class passed doesn’t implement IPoolable, that means we wouldn’t even be able to create a pool for it. If there isn’t a pool for it, then we definitely catch this case in our if statement at the beginning of the function.

We can now modify our Main class and use the object pool! Check it out:

private function init(e:Event = null):void 
{
	removeEventListener(Event.ADDED_TO_STAGE, init);
	// entry point
	stage.addEventListener(MouseEvent.CLICK, createParticles);
	addEventListener(Event.ENTER_FRAME, updateParticles);
	
	_oldTime = getTimer();
	
	ObjectPool.instance.registerPool(Particle, 200, true);
}

private function createParticles(e:MouseEvent):void 
{
	var tempParticle:Particle;
	
	for (var i:int = 0; i < 10; i++)
	{
		tempParticle = ObjectPool.instance.getObj(Particle) as Particle;
		tempParticle.x = e.stageX;
		tempParticle.y = e.stageY;
		
		addChild(tempParticle);
	}
}

Hit compile and profile the memory usage! Here’s what I got:

Very good memory usage

That’s kinda cool, isn’t it?


Step 9: Returning Objects to the Pool

We have successfully implemented an object pool that gives us objects. That’s amazing! But it isn’t over yet. We’re still only getting objects, but never returning them when we don’t need them any more. Time to add a function to return objects inside ObjectPool.as:

public function returnObj(obj:IPoolable):void
{
	var qualifiedName:String = getQualifiedClassName(obj);
	
	if (!_pools[qualifiedName])
	{
		throw new Error("Can't return an object from a pool that hasn't been registered!");
		return;
	}
	
	var objIndex:int = PoolInfo(_pools[qualifiedName]).items.indexOf(obj);
	
	if (objIndex >= 0)
	{
		if (!PoolInfo(_pools[qualifiedName]).isDynamic)
		{
			PoolInfo(_pools[qualifiedName]).items.fixed = false;
		}
		
		PoolInfo(_pools[qualifiedName]).items.splice(objIndex, 1);
		
		obj.destroy();
		
		PoolInfo(_pools[qualifiedName]).items.push(obj);
		
		if (!PoolInfo(_pools[qualifiedName]).isDynamic)
		{
			PoolInfo(_pools[qualifiedName]).items.fixed = true;
		}
		
		PoolInfo(_pools[qualifiedName]).active--;
	}
}

Let’s go through the function: the first thing is to check whether there’s a pool of the object that was passed. You’re used to that code – the only difference is that now we’re using an object instead of a class to get the qualified name, but that doesn’t change the output).

Next, we get the index of the item in the pool. If it’s not in the pool, we just ignore it. Once we verify that the object is in the pool, we must break the pool at where the object is currently at and reinsert the object at the end of it. And why? Because we’re counting the used objects from the beginning of the pool, we need to reorganize the pool to make all returned and unused objects to be at the end of it. And that’s what we do in this function.

For static object pools, we create a Vector object that has fixed length. Due to that, we can’t splice() it and push() objects back. The workaround to this is to change the fixed property of those Vectors to false, remove the object and add it back at the end, and then change the property back to true. We also need to decrease the number of active objects. After that, we’re done returning the object.

Now that we have created the code to return an object, we can make our particles return themselves to the pool once they reach the end of their lifetimes. Inside Particle.as:

public function update(timePassed:uint):void
{
	// Making the particle move
	x += Math.cos(_angle) * _speed * timePassed / 1000;
	y += Math.sin(_angle) * _speed * timePassed / 1000;
	
	// Small easing to make movement look pretty
	_speed -= 120 * timePassed / 1000;
	
	// Taking care of lifetime and removal
	_lifeTime -= timePassed;
	
	if (_lifeTime <= 0)
	{
		parent.removeChild(this);
		
		ObjectPool.instance.returnObj(this);
	}
}

Notice that we added a call to ObjectPool.instance.returnObj() in there. That’s what makes the object return itself to the pool. We can now test and profile our app:

Awesome memory usage

And there we go! Stable memory even when hundreds of clicks were made!


Conclusion

You now know how to create and use an object pool to keep your app’s memory usage stable. The class we built built can be used anywhere and it’s really simple to adapt your code to it: at the beginning of your app, create object pools for every kind of object you want to pool, and whenever there is a new keyword (meaning the creation of an instance), replace it with a call to the function that gets an object for you. Don’t forget to implement the methods that the interface IPoolable requires!

Keeping your memory usage stable is really important. It saves you a lot of trouble later in your project when everything starts to fall apart with unrecycled instances still responding to event listeners, objects filling up the memory you have available to use and with the garbage collector running and slowing everything down. A good recommendation is to always use object pooling from now on, and you’ll notice your life will be much easier.

Also notice that although this tutorial was aimed for Flash, the concepts developed in it are global: you can use it on AIR apps, mobile apps and anywhere it fits. Thanks for reading!

  • http://eddie-moore.com Ed Moore

    Hey great tutorial!
    I’ve been wondering about object pooling for a while now. Haven’t had the chance to try it out yet though, but your tutorial will help a lot when I do.

    Thanks :)

  • Brent

    Great tutorial thanks! Tho I noticed in step 2 that the peak is only 548kb not mb, unless i missed something :P

    • http://michaeljameswilliams.com/ Michael James Williams

      I think that the dot represents a thousands separator, in this case.

      • http://www.danielsidhion.com Daniel Sidhion
        Author

        Yeah! I’m sorry for not explaining it, but I’m in a country that uses dots as thousands separators.

  • guest

    2 ugly and useless things: IPoolable interface and singleton.

    1 important thing is missing: factory.

    This article has total score of “-3″ and it’s more bad then good.

    • http://www.rcdmk.com RCDMK

      You are so knowledgeable and couldn’t identify yourself for us to follow your highness.
      (This was a bit of sarcasm, for those who didn’t got it.)

      If you don’t have the guts to write a good tutorial explaining a better way of doing this, at least identify yourself when you do your crictics and explain the “why”s of your comments.

  • Jon T

    Great tutorial, I’ve been thinking about creating similar object pool for my game to reduce fragmented memory. I’m creating lots of QuadTrees to manage my terrain engine and the memory can get crazy.
    A lot of people will definitely benefit from this tutorial :)

    Thanks!

  • http://keith-hair.net/blog Keith H

    Good post. You took time to briefly explain some extra terms

  • Jose Gomez

    This is basicly a way to apply caché on action script isn’t is?

  • http://www.danielsidhion.com Daniel Sidhion
    Author

    @Jose Gomez: if you look at the very basic purpose of cache (to store something to make future requests to this content easier to get), then it’s similar. Object pooling serves as a way to increase performance (creating instances generally takes some processing) and to keep the memory usage stable, so when you request an object from the pool it retrieves this object very quickly (cache), but it also has the advantage of helping you control the memory usage.

    @All: Thank you a lot for your comments!

  • http://www.rcdmk.com RCDMK

    Hi, nice tut.

    I’m having a little problem and couldn’t find out what is causing it:

    On the “registerPool” method, in the check for “IPoolable”, the condition ever returns false, thus never instantiating a pool.

    When I trace “describeType(objectClass).factory.implementsInterface” i get:

    But when I trace “describeType(objectClass).factory.implementsInterface.(@type == ‘objectPooling::IPoolable’)” i get nothing.

    Any idea?

    • http://www.rcdmk.com RCDMK

      Oh WP troll me every time.

      I get this when trace “describeType(objectClass).factory.implementsInterface”:

      <implementsInterface type=”flash.events::IEventDispatcher”/>
      <implementsInterface type=”flash.display::IBitmapDrawable”/>
      <implementsInterface type=”com.rcdmk.objectPooling::IPoolable”/>

    • http://www.rcdmk.com RCDMK

      Hi, nevermind. I’ve found this is a XMLList of nodes without values, thus, it prints emptystrings.

  • http://none 微微

    i have carefully read your great tutorial,but can you tell me why the memory of your demo keeps on raising when i just watch it and do nothing?have you ever recognized thst?very strange…
    thanks again

    • http://www.danielsidhion.com Daniel Sidhion
      Author

      Hello 微微!

      That’s because the app is running in the browser’s flash player. According to the documentation ( http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/system/System.html#privateMemory ) for flash player there is a way to view only the memory used by container application, so you’ll view the memory usage of not only your flash app, but also the usage of all other flash apps in the page (such as ads) and other pages too.

      Thank you for your comment!

      • http://michaeljameswilliams.com/ Michael James Williams

        Looks like our advertisers need to read this tutorial, then :)

  • gerry

    Hi.
    This is brilliant but is NOT for beginners.
    Can we use object pooling when we use spritesheets for the animation or is the above only for when we are using moveclips on the timeline?

  • http://bhbooker.com Booker

    Question: does anyone know if the memory in Vector is contiguous? Because if so, splicing and pushing it like this would be very un-optimized. This might actually perform better as a standard array. I attended a presentation at AdobeMax last year with Lee Brimlow where he talked about object pooling and built a similar system to the one here. (using a vector and splicing it) I approached him after the show and asked if the memory was contiguous in Vector and he didn’t seem to know the answer. I’m thinking he might now though because if you check gotoAndLearn http://gotoandlearn.com/play.php?id=160 (his video tut blog) you’ll see that he recommends using Array instead of Vector. Honestly it kind of looks like the best option would be to put a next pointer in your iPoolable and turn the thing into a singly linked list. Thoughts?

  • Raphael Bastos

    First, thanks for the tutorial! It was pretty helpful.

    I’m implementing this pool on my project but I’m not sure how to adapt it to use as a movieclip pool. Since the instances of my MovieClip don’t have the “renew” and “destroy” methods, how would that work? Do I have to create a class, create a new movieclip on its constructor and implement those methods?