Back in March of 2008 I published an object pooling utility class that allow you to place objects into a collection and use them when needed. That class came handy on a recent project where I had to use few instances of DataGrid, which is known to be one of the most expensive components in Flex which many believe should be avoided at all cost. The app I built had to create instances of data grid during runtime and than remove them from the display object. Object pooling is a great design pattern to handle these cases where you need to use the same object over again and again.
The reason is that object creation takes much resources and should be avoided in cases where you need the object often. I looked over the class and although I wrote it in 2008 it is still in good shape. One thing I noticed is that it was using an ArrayCollection. I have upgraded the class to use a Dictionary instead of ArrayCollection using a HashCollection utility class I developed which is using the Dictionary with a weak reference.
Download and look at the ReusablePool utility class:
http://code.google.com/p/eladlib/source/browse/trunk/EladLibFlex/src/com/elad/framework/objectpoolmanager/ReusablePool.as
To implement the class and show you an example I will be using an application that uses three objects: video, image and a list component. When you add the element to the application and then remove it and keep adding these objects agains and again you put a memory expense and you can see a small hickup. However, when you are using Object pool you keep the memory usage low since the objects are cached and you save on the object instantiation cost. As you can see the application is running smoothly while adding and removing objects from the display.
The complete implementation code can be seen below:
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/halo"
minWidth="1024" minHeight="768"
creationComplete="setObjects()"
viewSourceURL="srcview/index.html">
<fx:Script>
<![CDATA[
import com.elad.framework.objectpoolmanager.Reusable;
import com.elad.framework.objectpoolmanager.ReusablePool;
import mx.collections.ArrayCollection;
import mx.containers.Canvas;
import mx.controls.Image;
import mx.controls.VideoDisplay;
import mx.core.UIComponent;
import net.hires.debug.Stats;
private var reusablePool:ReusablePool = ReusablePool.getInstance();
private var canvas:Canvas = new Canvas;
private function setObjects():void
{
// adding stats
component.addChild( new Stats() );
addElement(component);
// adding the object to the collection
reusablePool.setReusable( new Reusable(createUI(), "FlexImage") );
// adding an array object
reusablePool.setReusable( new Reusable(createArray(), "arrayList") );
// adding video UI object
reusablePool.setReusable( new Reusable(createVideoUI(), "videoUI") );
this.addElement(canvas);
}
private function useUIObject(name:String):void
{
// getting the collection
var reusable:Reusable = reusablePool.acquireReusable(name);
var component:UIComponent = reusable.object as UIComponent;
// use the object
canvas.removeAllChildren();
canvas.addElement(component);
// return collection back to the pool of objects
reusablePool.releaseReusable(reusable);
}
private function useArrayObject():void
{
// getting the collection
var reusable:Reusable = reusablePool.acquireReusable("arrayList");
var dp:ArrayCollection = reusable.object as ArrayCollection;
list.dataProvider = dp;
// return collection back to the pool of objects
reusablePool.releaseReusable(reusable);
}
private function noCacheArrayObject():void
{
var dp:ArrayCollection = createArray();
list.dataProvider = dp;
}
private function noCacheUIObject():void
{
canvas.removeAllChildren();
canvas.addElement(createUI());
}
private function noCacheVideoUIObject():void
{
canvas.removeAllChildren();
canvas.addElement(createVideoUI());
}
private function createUI():UIComponent
{
var image : Image = new Image();
image.source = "http://blog.digitalbackcountry.com/wp-content/uploads/flash_builder_logo.png";
image.width = 400;
image.height = 300;
image.x=10;
image.y=300;
return image;
}
private function createVideoUI():UIComponent
{
var videoDisplay:VideoDisplay = new VideoDisplay();
videoDisplay.source = "http://kakonacl.dip.jp/PlayerTry/TestMovies/FLV/FLV4/Flash.flv";
videoDisplay.x = 10;
videoDisplay.y = 300;
videoDisplay.width = 300;
videoDisplay.height = 300;
return videoDisplay;
}
private function createArray():ArrayCollection
{
var array:ArrayCollection = new ArrayCollection();
for (var i:int=0; i<10000; i++)
{
array.addItem({label: i});
}
return array;
}
]]>
</fx:Script>
<s:Label x="10" y="10"
text="These examples shows memory usage with using the object pooling collection and without it."
fontWeight="bold" height="33"/>
<s:Label x="10" y="61"
text="Cached Object Pooling" width="200" fontWeight="bold"/>
<s:Button x="10" y="87"
label="UIobject"
click="useUIObject('FlexImage');" width="200"/>
<s:Button x="10" y="117"
label="array"
click="useArrayObject();" width="200"/>
<s:Button x="10" y="147"
label="Video UI"
click="useUIObject('videoUI');" width="200"/>
<s:List id="list"
x="325" y="79"
width="126" height="200" />
<s:Label x="10" y="178"
text="Regular objects" width="200" fontWeight="bold"/>
<s:Button x="10" y="202"
label="UIobject"
click="noCacheUIObject();" width="200"/>
<s:Button x="10" y="232"
label="Array"
click="noCacheArrayObject()" width="200"/>
<s:Button x="10" y="262"
label="Video UI"
click="noCacheVideoUIObject()" width="200"/>
<mx:UIComponent id="component" x="237" y="83" width="70" height="100"/>
</s:Application>
To measure the memory usage you can use the small statistic class that was developed by Mr.doob. Additionally, you can take a look at the Eclipse Profiler. In first scenario where I add an element to the application and remove it, the profiler shows as if we have a memory leak since the usage peaked to the “red” lines. I am not saying this is a memory leak, but I am pointing out that the memory usage is high since the objects were removed but haven’t been picked up by the GC yet. As you know using the removeAllChildren() remove the object from the component but is not necessarily ensure the GC will come and release the memory right away. See Profiler screen shot below:

In the second scenario, the objects are cached and I am not putting any memory constrains on my application. See figure below.

The utility class can be limited to the amount of objects you want to store, plus you can tie the class to a logic that will clear all the objects when needed.
Let’s take a look at the code to create an instance of the utility class and add an object.
The utility class is a singleton so we can use the same object through the life cycle of the application.
private var reusablePool:ReusablePool = ReusablePool.getInstance();
To add an object you create a Reusable object that holds the object and the name of the object:
// adding the object to the collection reusablePool.setReusable( new Reusable(createUI(), "FlexImage") );
When you are ready to retrieve the object use the acquireReusable method, which will remove the object from the object collection:
// getting the collection var reusable:Reusable = reusablePool.acquireReusable(name); var component:UIComponent = reusable.object as UIComponent;
When you are done and want to send the object back to the object pool collection use:
reusablePool.releaseReusable(reusable);
Cheers


























