boostworthyisryantaylor

AS3: Allocator For Object Caching

I was recently reading Nicolas’ most recent post on Flash 9 optimizations and I noticed that he had mentioned the use of an ‘Allocator’ class to help cut back on object instantiation. I actually have something along those lines in my personal framework, so I thought I would share it with you all.

First, a little bit about the subject. In an application in which you are constantly creating new objects, whether it be display objects or otherwise, you are going to suffer from a few different problems…

The first problem is performance. Creating new objects is somewhat slow, especially if their initialization process contains a lot of code. Performance is also affected by garbage collection. The more objects that are created, temporarily used, then left for garbage collection, the more that Flash Player has to work to clean up after your mess. This type of strain can be seen on the processor if you are monitoring processor load.

The second problem is memory. If you are constantly creating new objects for temporary use, the odds increase that you will screw up somewhere and things won’t get garbage collected properly. When this happens, it is called a memory leak. This is a pretty serious problem because potentially it could cause your application to crash along with the browser and maybe even the user’s machine.

You can cut back on these types of issues by simply keeping a close eye on your application piece by piece from the very beginning of development on a given project. Tools such as the Flex Builder profiler and the use of utilities such as ‘getTimer’ for timing chunks of code will help you a lot during this process. Depending on the complexity of your application, you may wish to take things a bit further to really help control the amount of new objects being created. That’s where my ‘Allocator’ class comes into play.

The ‘Allocator’ class is pretty simple; it’s composed of an array for caching objects, an index for tracking position within the cache, and a class type that the allocator instance is responsible for caching. Usage is pretty straightforward:

ActionScript
< view plain text >
  1. // Create a new allocator instance.
  2. // The constructor argument is the class type
  3. // in which the allocator will handle caching for.
  4. // For the sake of example, I am working with a
  5. // class called 'MyModel'.
  6. var allocator:IAllocator = new Allocator(MyModel);
  7.  
  8. // Get some instances of the MyModel class.
  9. // Since these are the first instances being
  10. // requested, they are being created and cached
  11. // before being returned.
  12. var modelA:MyModel = allocator.getObject();
  13. var modelB:MyModel = allocator.getObject();
  14. var modelC:MyModel = allocator.getObject();
  15.  
  16. // Internally, this resets the cache index.
  17. // You do this once you have finished getting
  18. // a set of objects from the cache.
  19. allocator.reset();
  20.  
  21. // This time around, three MyModel instances
  22. // already exist in the cache, so no new objects
  23. // are created. The existing objects are re-used.
  24. modelA = allocator.getObject();
  25. modelB = allocator.getObject();
  26. modelC = allocator.getObject();

In practice, this type of workflow is ideal for a Flex application in which you are binded to data which is constantly changing. Rather than creating new model objects upon each data refresh, you create them once, then recycle each model object by passing the existing objects the new data. The sample files I have prepared for inclusion with the ‘Allocator’ source files demonstrate a basic model architecture that lends itself nicely to all of this.

Also worth noting is the performance numbers resulting from the included test file. The test runs two for-loops; the first one creates and caches the objects as the requests are made to the allocator for the first time. Next, the allocator is reset, then the second loop once again requests instances from the Allocator. Here are the results:

Initial -> Time: 0, Memory: 6815744
loop #1 -> Time: 20, Memory: 7467008
loop #2 -> Time: 22, Memory: 7467008

Notice that the first loop took 20 milliseconds and memory increased. The second loop only took 2 milliseconds and memory did not increase. Ten times the performance and no temporary memory increase is exactly why the Allocator is so useful.

Download ‘boostworthy_alloc_src.zip’

Hopefully you will find this stuff useful in your projects. Feel free to share any questions or comments that you may have.

7 comments

7 Comments so far

  1. Og2t March 10th, 2008 4:40 am

    Great post Ryan! I’m going to play with your IAllocator class for a bit and will give a feedback later.

  2. hadrien March 17th, 2008 5:18 pm

    Thank you!

  3. Johnny Michaelsen March 29th, 2008 8:47 pm

    Thank u so much for sharing this! Looks very interesting :)

  4. Paul April 8th, 2008 6:59 am

    Hey

    Thanks for the post and code – interesting, I haven’t really felt the need to use this kind of allocator before, although I’ve been aware of the technique.

    I’m starting to write more games now though, so the performance gained by using an allocator are worth investigating.

    I downloaded your example and I get similar results to yours. One thing though; in your loop tests you are overwriting the same model variable with each iteration.

    However, if I try the same test but fill an array with the MyModel objects I see an increase in memory usage after the second loop.

    Do you have any idea why this would be the case?

    Here’s my test code (I’m not sure if my formatting will be preserved):

    import com.boostworthy.example.MyModel;
    import com.boostworthy.utils.alloc.Allocator;
    import com.boostworthy.utils.alloc.IAllocator;

    import flash.utils.getTimer;

    const LENGTH :int = 10000;

    var allocator :IAllocator = new Allocator(MyModel);
    var data :XML =

    function init():void
    {
    var model :MyModel;
    var time :Number = getTimer();

    var modelHolder:Array = [];

    trace(“Initial -> Time: ” + String(getTimer() – time) + “, Memory: ” + System.totalMemory);

    for(var i:int = 0; i Time: ” + String(getTimer() – time) + “, Memory: ” + System.totalMemory);

    allocator.reset();

    modelHolder = [];

    time = getTimer();

    for(var j:int = 0; j Time: ” + String(getTimer() – time) + “, Memory: ” + System.totalMemory);

    }

    init();

  5. Paul April 8th, 2008 7:01 am

    Nope, formatting totally screwed and some code has been removed from my above post. Basically, try your same test but using arrays.

  6. Ryan Taylor April 8th, 2008 3:33 pm

    Hey Paul,

    Overwriting the variable in each iteration is fine; I’m simply using it to temporarily store a reference to the allocated object for readability. If you prefer, you could also do something like this as well:

    MyModel(allocator.getObject()).setData(data);

    In a real world example, you would also maintain some sort of collection that contains references to the objects that have been allocated, rather than ever using the object directly from the Allocator like in the example above.

    It wouldn’t make sense for the use of an array to increase memory, as the Allocator itself uses an array internally. Nonetheless, I went ahead and edited my example file with the use of an array instead of the Allocator and found no increase in memory. Since your code failed to display properly, maybe shoot me an email and I can take a look at it for you.

  7. Paul April 10th, 2008 12:10 pm

    Hey Ryan

    Thanks for responding – I have worked out what is causing the increase in memory usage in my test and it is unrelated to the allocator.

    I was creating an array and filling it with MyObjects in the first loop and then clearing out the array and reusing it in the second loop. If I take out the array clearance and just overwrite the existing array there is no memory increase.

    var myArray:Array = new Array();

    first loop

    myArray = new Array(); //

Leave a reply

*
To prove you're a person (not a spam script), type the security word shown in the picture. Click on the picture to hear an audio file of the word.
Anti-spam image