Tweening and object pools

Some days ago I was writing a tween engine for our library here at Hobnox and when I was comparing it with the other ones out there which are quiet popular (Tweener, TweenLite) I was pretty surprised that my engine was performing about 10fps faster than TweenLite when tweening 1000 objects. It was 40fps for me, 28fps for TweenLite and 14fps for Tweener. It is not only faster but the memory usage is constant and small — on a Mac it was constant 11mb for my engine versus up to 22mb for TweenLite for instance.

Since I am currently not allowed to post the source-codes I want to talk a little bit about the ideas behind the engine.

If you want to make use of AS3 and it’s features you have to do two simple things: reuse your objects and keep it type safe.

So making your engine type safe is actually quite easy if you think about it. If you build a modular tween engine which is able to handle plugins and tween any property of any object you write a plugin for a property of an object which is then handling all the logic. The tween itself is not doing anything actually but updating all its plugins with a normalized value.

All the plugins are stored in a linked list which is simply the fastest way to iterate over all of them. But what is more important is object pooling!

It is a very common practice to use pools of objects in other languages. If you know Java well you probably came across thread-pools or memory pools in C++ in general. So why are those guys doing it? Well it is simple: creating objects and reserving memory is always a very expensive task. That is for instance why Flash is also allocating more memory than your application is using if you did not notice it already.

So how does it work? It is quite simple. You allocate a defined number of objects and put them in a pool. If you need an object you take it out of the pool. Once you are done and do not need the object any longer you do not completly destroy it (of course you should clean all references to other objects) but you put it back into the pool where the object is then waiting to be used again. That will save you the cost of initializing new objects every time. It will also not hurt the garbage collection. So you may ask what you are doing once the pool is empty because you are using all the objects. Usually the most simple answer is: grow it by a defined rate. You will then create once more instances. If you think about the 1000 tweens changing x, y, scaleX, scaleY, rotation and alpha this makes in my case six properties times 1000 = 6000 objects. Now if I would recreate 6000 objects every time that would cost me a whole lot of performance and the garbage collection would not be that happy either.

Here is a simple snippet of how you could implement an object pool:


package
{

	/**
	 * @author Joa Ebert
	 */
	public final class TweenPool
	{
		private static var DEFAULT_GROWTH_RATE: int = 0x10;
		private static var DEFAULT_CAPACITY: int = DEFAULT_GROWTH_RATE << 1;

		private static var _counter: int;
		private static var _pool: Array;

		private static function initialize(): void
		{
			_pool = new Array( DEFAULT_CAPACITY );

			var i: int = DEFAULT_CAPACITY;

			while( --i > -1 )
				_pool[ i ] = new Tween();

			_counter = DEFAULT_CAPACITY;
		}

		public static function createTween( /* parameters */ ): Tween
		{
			if( 0 == _counter )
			{
				var i: int = DEFAULT_GROWTH_RATE;

				while( --i > -1 )
					_pool.unshift( new Tween() );

				_counter = DEFAULT_GROWTH_RATE;

				return createTween( /* parameters */ );
			}
			else
			{
				var tween: Tween = _pool[ --_counter ];

				/* initialize tween with parameters here */

				return tween;
			}
		}

		public static function releaseTween( tween: Tween ): void
		{
			_pool[ _counter++ ] = tween;
		}

		{
			initialize();
		}
	}
}

So whenever you want to create a tween you would call TweenPool.createTween() instead of new Tween. And in your dispose() method of the Tween class you would simply write TweenPool.releaseTween(this) and you are done.

Now you could make that code already much smarter. You could use a linked list in your pool to store the objects and get rid of the array manipulations. You could also make the growth smarter etc. Remember that there might be the time when you tweened once 10.000 objects but just one time so you want to be able to reduce your pool again.

I hope you get the idea. Making a pool of your objects is quite simple. I used it also in some other applications when I had to run an algorithm that was making heavy use of a lot of objects and it is definitly worth the effort.

Related Posts

23 Responses to “Tweening and object pools”


  1. 1 Gabriele Farina

    Hi Joa,

    actually Object Pooling is one of the best practice you can use when dealing with multiple objects. Hope that Adobe guys understand it and will improve their libraries accordling, because there are many code portions that could be updated that way.

    A general but typesafe ObjectPool class could be very useful … having “type parameters” in AS will be great for that :) … waiting for AS 4 :P

  2. 2 joa

    Using a linked list is a great alternative to typed arrays :) For a generic object pool we will definitly need template types / generics. Right now I did it with an interface ala Pool.init( Class ) while class has to implement the interface the pool can deal with.

  3. 3 Gabriele Farina

    The problem is that Class is not really typesafe. isn’t that better to provide a generic factory instance to have compile time type safety ?

    IE (just an example – even if I know that you understand what I mean :P):

    interface IPoolableObject
    {
    function init( initObj: Object ): void;
    function dispose(): void;
    }

    interface IPoolableObjectFactory
    {
    function create( initObj: Object ): IPoolableObject;
    }

    class ObjectPool
    {
    public function ObjectPool( factory: IPoolableObjectFactory ) { … }
    public function create( initObj: Object ): IPoolableObject;
    public function release( object: IPoolableObject ): void;
    }

    class MyObject implements IPoolableObject { … }

    class MyFactory implements IPoolableObjectFactory { … }

    var pool: ObjectPool = new ObjectPool( new MyFactory );

    This requires 1 more function call only when u have to create a new instance of the object, which shouldn0t happen frequently.

  4. 4 joa

    Your right, but you would have to create a new factory for each object type again. It would not be that much to code but I was just lazy :)

  5. 5 Gabriele Farina

    eheh :)

    As lazy as everyone outta there. I did the same as you so don’t worry ;)

  6. 6 ickydime

    Have you guys checked out GoASAP for your custom tweener? http://www.goasap.org/

    I was curious to see if you used it, if it was helpful, or if you preferred just writing from scratch.

  7. 7 sck

    FYI, the pre-decrementers in the createTween method are missing the extra minus sign.

  8. 8 joa

    Yes/no :) It is Wordpress making a stupid dash out of it.

    ickydime: I did not start with it at all. I think the open tween engines are all great for different purposes but to me I wanted to do it in a way that is clean in my opinion and not dependent on another developer outside of the office for such a simple thing. Since it is an in-house engine I could make use of a lot of other different tools that we have here which would not be possible without heavy modification on the core of GoASAP.

  9. 9 Gabriele Farina

    Yes, probably for simple and lightweight tweener that needs to work with a custom framework the best approach is to write your own. We did the same for some Aviary tools.

  10. 10 moses gunesch

    Hi Joa,

    GoASAP is certainly not another open tween engine like the others; it is far more like what you are talking about here – an extremely small and memory-efficient core system. It strips everything down to the barest of bones. One of its goals is to be universal, meaning that if you could not find a way to do what you wanted with it then it has failed to a degree. Another thing Go proposes is that we would all work together to figure out what the ultimate core system would be, and build systems from that, so that more systems would work together.

    Actually, the pooling class you show here could very easily be used with Go.
    When you say heavy modification of Go’s core… what are you specifically referring to? Please elaborate!

    (Thanks, and sounds like you’re doing really interesting work!)

  11. 11 joa

    Hi Moses,

    thanks for the reply — when I am talking about core modifications I am more talking about integrating it into our framework. All of our instances using some kind of clock are synchronized with a special class. So the tweens are also synchronized like that and I would have to change your whole clock part afaik to get it to work with ours because I see no need why a tween should be updated differently.

    Actually the Go framework could have done the same job of what I wanted. I had a chat today with Sebastian, the author of tweego and he definitly changed my perspective of Go because when I saw tweego I thought it is completly untyped — but in fact its not, which is great.

    I think you could tweak Go in a lot of directions anyways. Making use of smarter data structures. The pool I have in the example is a really poor example but I just wrote it down quickly for the post. Making use of a linked list is again better in that case.

    If you want you can contact me at j(?)je2050.de to share some ideas.

    Cheers

  12. 12 moses gunesch

    Thanks I will contact you…

    Yes it is a common mistake to see something produced with GoASAP, which is just a set of core classes, and mistake the end product for what Go is. It’s like if you saw a Cairngorm app and decided that you didn’t like that framework because of someone’s application build.

    Everything in Go is involved in *not* duplicating things that happen in every single animation system. There is a synchronization class at its core, for example. If 3 animation systems that use Go are used together they run incredibly efficiently even though they can all be entirely different in implementation because they are not fighting each other for performance, they can all be synchronized via the same timer.

    GoEngine is just a little bit of Go of course, it also provides other common elements that should not have to be redone every time like basic event types, play controls, etc., and it has a completely extensible manager layer that is unlike any other system out there because it does not encourage developers to “bake” management into code, instead keep it entirely “decoupled.” :-)

  13. 13 moses gunesch

    ps, Hobnox is really great!

  14. 14 ickydime

    Thanks for the great discussion. Had no clue that my initial question would pull in Moses into the discussion. Love how active/approachable the leaders in the Flash community are.

    Great work to you both.

  15. 15 sakri

    Hi Joa,

    Just wondering, if there has been any talk / thought into releasing your tween library to the masses? I’d like to animate some particles, and, well… :)

  16. 16 joa

    Sorry to disappoint you but we have currently other stuff to do …

  17. 17 Alan

    I read your blog, but just came across this post. With the updates to TweenLite, how is your engine compare. Especially since lately Tweenlite has incorporated the plugin architecture.

  1. 1 Tween engine comparison at blog.joa-ebert.com - Blog of Joa Ebert
  2. 2 Object Pooling at Logging Robby Abaya
  3. 3 Flex and Flash Developer - Jesse Warden dot Kizz-ohm » Blog Archive » Writing a Caching Engine for Flash Player
  4. 4 M4Tween, premier jet de moteur de tween pour minuit4 « Minuit4
  5. 5 Flex and Flash Developer – Jesse Warden dot Kizz-ohm » Blog Archive » Good Memory Management When Using PureMVC
  6. 6 Yi’s blog - 优化fLEX程序性能的各种方法

Leave a Reply