Object Pools

Let's take a quick dip in the object pool!

Wait, wait! Before you issue the command to fire, it is notcustomary to allow the condemned a few last words?

First a bit of background: there's this thing called garbagecollection that certain languages and libraries use to handleautomatic memory management. This way if you allocate a new object, youdon't have to worry about deallocating it—the garbage collector does itfor you at some point in the future when it's sure the object is nolonger "reachable" (i.e. referenceable or usable in any way).

Modern garbage collectors are pretty freakin' awesome, but from timeto time, they might decide to collect the garbage when it's notconvenient, and collecting the garbage might introduce delays. This canmanifest when you are creating and discarding a large number ofobjects very quickly. Anecdotal evidence around the web suggests thismight sometimes occur when doing 3D rendering and allocating largenumbers of temporary vector objects per frame; sometimes the frameratehitches while the garbage collector tries to clean up the mess.

Every goat in this diagram is currently inmemory. The ones in the pool are kept ready for use. When needed, theyare removed from the pool and put into service. When done, they arereturned to the pool.

The general solution is to stop allocating temporary objects, andreuse existing ones. You can keep a "pool" of unused instances ofobjects on stand-by, and just pull objects out of it when they areneeded. This way the garbage collector has a lot less work to do, sincenothing is every collected; every object is either in-use, or storedidle in the object pool.

Here Be Dragons. Remember when I said your garbage collector wasfreakin' awesome? It is. You should trust it and let it do its job. Infact, you could actually negatively impact performance by trying toout-perform it using an object pool.

But if you find sometime that you're experiencing garbage collectiondelays (which, mind you, look exactly like non-garbage collectiondelays), and that you're creating huge numbers of short-lived objects ina big hurry, you might consider switching to something like an objectpool to see if that helps.

For this object pool, I didn't allocate any goats in advance. If agoat is needed, the object pool is asked for one with a call toalloc(). The object pool first looks to see if there are anygoats in the free list, and if so, removes it from the free list andreturns it. If there are no goats in the free list, it simply allocatesone and returns it.

The opposite is free(). When the goat has finshed its job ofwalking across the screen, it is passed back to the object pool with acall to free(). The object pool adds it to the free list whereit will remain until called upon again.

So far, the memory allocator has been called a number of times inalloc(), but each goat is still referenced at all times. If inuse, the canvas renderer holds a reference to that goat. If not in use,the object pool holds a reference to it. So the goat will never begarbage collected.

Playtime: Decrease the spawn delay to 0.5 seconds, and let abunch of goats spawn and run. Notice that the number of allocated goatsquickly increases as more are brought into existence. But then noticehow the number stabilizes as the pool grows large enough for our needs.

Increase the delay to 1.0 seconds, and you'll see how we begin usingfewer goats. The rest remain on standby in the pool in case we needthem.

After a bit, set it back to 0.5. Less spawn delay means more goats,and they are again drawn from the pool; note that the total numberallocated remains the same.

I've clamped the spawn delay so you can't go too nuts with it. Howlow can you make it until your browser starts to choke? Because,honestly, can one ever have too many goats?

No. The answer to that question is "no".

Lastly, you might notice a button in the lower right of the apptitled "Collect". This button nukes the free list in the object pool.This can be useful in certain cases where the pool was needlessly large.Keep in mind, though, that there are still goats in existence (used bythe canvas renderer). The renderer just returns these to the pool,which adds them back into the freelist as if nothing had ever happened.

Implementation

For the object pool, we need to be able to add objects to the pooland remove them from it. Plenty of data structures could be used forthis, and the exact one you choose might be language-dependent. In thiscase, in JavaScript, I used an Array treated like a stack(using the push() and pop() methods).

What kinds of things can be stored in the pool? In thisimplementation, you tell the object pool what class of object it will becomposed of by passing the constructor to the pool.

 
JavaScript
// constructor of Goat objects function Goat() { this.init(); } // Goat object init function: Goat.prototype.init = function(happyLevel) { this.happyLevel = happyLevel; } // make a new object pool of Goats: var goatPool = new ObjectPool(Goat); var goat1 = goatPool.alloc(10); // goat happy level 10 var goat2 = goatPool.alloc(20); // goat happy level 20 var goat3 = goatPool.alloc(30); // goat happy level 30 goatPool.free(goat2); // return goat2 to the pool

It's important to note, however, that there aren't normal goats.Dum dum duuum! They implement a particular interface that theObjectPool expects to be there, namely the init()method. Why?

Well, since we might not actually be allocating a new Goatinstance (since we could be just grabbing one from the pool), thatgoat's constructor isn't necessarily going to get called. So how to youinitialize it? In this case, we take the arguments passed toalloc(), and pass them as-is into the goat's init()method. You also might have noticed that the goat's constructor itselfcalls the init() method, too! init() is acting as asurrogate constructor in this case.

Misc Notes

Some Array methods create new arrays, so it's important tosteer clear of those. You don't want to be inadvertently creatingtemporary objects in your attempt to avoid creating temporary objects!

Another important safety tip is that you should zero out your objectwhen it is returned to the pool. The object might have importantinformation in it, like the goat's bank account number, and it would bebad if an evil goatherd attacker grabbed that goat from the object pooland read its secret information. Because the risk is high, the objectpool itself should zero the object.

Every language has a best way to do this. In this JavaScriptimplementation, the object pool's free() method iteratesover the properties of the object and deletes them. (Of course,if the object has properties that aren't enumerable, they won't becaught by this trick.) To be extra paranoid, it then callsinit() with no args, so that method needs to be prepared forthat and obliterate data as appropriate.


http://beej.us/blog/data/object-pool/

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值