By the way there are some points that I want to make clear: first this article will be -as all the stuff about memory management- boring and long. You will not need Object Pooling all the time if you are not developing a game or you don't need to do heavy computations with a fluid ui. Besides, Object Pooling is a method which has gainings as much as disadvantages. Moreover I will not give the details of taking the CPU/RAM profile and examining the timeline because those requires their very own articles. However being familiar with these (Chrome Documentation) will help you to understand the rest of the article better.
Before diving into the code, knowing where the problem is coming from will be very helpful for us to solve the problem. When we examined the timeline we came across with an image like below. Of course there may be any other causes but this is the one in our scenario.
If you look closer to the graph above there is an obvious connection in decrease of the FPS count (green) and RAM usage (blue). Why that decreases in RAM usage causes decrease in FPS count? The first thing we should remember in problems related to RAM usage: Garbage Collector.
Garbage Collection (GC) is a form of automatic memory management. The garbage collector, or just collector, attempts to reclaim garbage, or memory occupied by objects that are no longer in use by the program. source
When we look into the details we see we are right. In the picture below you can see that when only one Garbage Collector comes, 126 mb memory is cleaned and it almost takes 1 sec. If we think that when Garbage Collector is working, all the other operations (animations, user interactions...) are paused; that's too much time.
That means: we are producing lots of garbage and we need some sort of recycling. In RAM usage the pattern (regular increases and sudden decreases) you see above generaly are not the good news. Relatively, the straight line means that we are using the RAM efficiently.
Let's think that we are developing a particle system showing 50 particles at the same time and every particle is an instance of the Particle Class. When a particle gets invisible (when it gets off the screen) we remove its reference since we don't need this object anymore. Also since an another particle will appear, we need to instantiate a new instance. There are 2 basic problems in here. Firstly, since the instance we removed its reference will not be used anymore, when Garbage Collector comes it will waste the time to clean this area. And the second problem is; we will bump into the instantation overhead of the new Particle instance.
Now that we identified the problem, we can solve it. Object Pooling is a method which you create as many objects as you will need at a given time portion and keep them in a pool then use the objects from there when needed.
From now on, I think it will be more effective to go on with some code examples. This example demoes the problem we mentioned at the first section:
See the Pen pgYXPo by Burak Can (neoberg) on CodePen.
If you look closely we instantiate every Particle instance when we need. For demo purposes, we push every Particle instance we instantiated to an array named
particles. After a while we remove their references by cleaning the array to let Garbage Collector to collect them.
The following code demonstrates the most basic Object Pooled version of the first example:
See the Pen yewdKe by Burak Can (neoberg) on CodePen.
I will not dive deep into the details of the code. As you can see already, it is implemented at its simplest. Also you can observe the performance difference clearly.
When we talk about the basic idea we can say that firstly we have a warming process. This is basically the operation that we fill the pool for the first time. We create the objects that we will need and we push them into the pool. Instead of creating new instances everytime, we use these ones when we need by taking them from the pool with PooledClass.getInstance().
When we finish with these objects we push them back to the pool using PooledClass.release(instance). This method turns the object into its initial state and puts back to the pool.
In this way by creating less garbage that Garbage Collector needs to collect; we gain a great performance improvement. Also we get rid of the instantiation overhead. You can see the graph of Pooling applied example below:
As we can see FPS count is consistently about 60FPS. In other words we got rid of the freezes and slowness that we mentioned before!
If you have read until here without getting bored, thanks for reading. I hope I made you spend a useful time :)