Just start typing...
Technologies

New Pooling API in Unity 2021

Published January 31, 2022

In games in most cases you are faced with a lot of instantiations and disposes of objects but when you reach some amount of instantiations every second performance can degrade dramatically.

To deal with it you have several options:

  • Reduce amount of instantiating objects per second
  • Buy some pooling system in Asset Store
  • Implement your own pooling system
  • Use new Unity Pooling API

Yes, Unity 2021+ has a great built-in pooling API and we are going to talk about it in this article.

Object Pool

The object pool is a well known creational design pattern. The main idea is that right after start the pool contains a list of already instantiated objects. When in a program you need a new instance of a specific object you do not directly instantiate it instead you ask the object pool for it and when you already do not need it you return it back to the object pool.

In case of using object pool we have no instantiations and dispose all the time it means no memory allocations so for the garbage collector much less work here (and no micro-freezes).

UnityEngine.Pool

The UnityEngine.Pool namespace contains several pools:

  • CollectionPool<T0,T1>
  • DictionaryPool<T0,T1>
  • GenericPool<T0>
  • HashSetPool<T0>
  • LinkedPool<T0>
  • ListPool<T0>
  • ObjectPool<T0>
  • UnsafeGenericPool<T0>

CollectionPool<T0,T1>

This is the base implementation of object pool for collections like Dictionary (DictionaryPool<T0,T1>), List (ListPool<T0>), HashSet (HashSetPool<T0>).

Base CollectionPool<T0,T1> and derived classes have the same static API.

  1. Public static TCollection Get()
  2. Public static PooledObject<TCollection> Get(out TCollection value)

As an example let’s assume that you need to generate geometry at runtime, so you often need a few collections like List<Vector3> to store generated vertices and you need to run generation periodically. In that case you can use ListPool<T0>:

var vertices = ListPool<Vector3>.Get();
    GenerateMesh(vertices);
    ListPool<Vector3>.Release(vertices);

Example of using ListPool

GitHub source code

As you can see, using ListPool<T0> is very simple:

  1. Get a list from the pool
  2. Use the list as you want
  3. Return the list back to the pool

The pool clears the list when it is returned back to the pool.

This approach is good if you need to keep a list for a while but in case when you need a list in one place in one frame CollectionPool has a shorter way:

using (var pooledObject = ListPool<Vector2>.Get(out List<Vector3> vertices))
{
    GenerateMesh(vertices);
}

Example of using ListPool with using operator

GitHub source code

When the pooled object leaves the scope it will be Disposed and returned to the pool automatically.

Usage of CollectionPool is easy but you don’t have control on how an object is created, initialized and deinitialized.

ObjectPool<T0>

The ObjectPool<T0> was created to allow you to have full control of how objects are created, initialized and deinitialized.

In many cases you need a pool for GameObjects so the example below will be for GameObject.

To create an instance of ObjectPool the first thing you need is to define how to create an object which will be in the pool.

GameObject CreatePooledItem()
{
    var pooledGameObject = new GameObject("Pooled GameObject");
    // Add components or set other properties
    …
    return pooledGameObject;
}

You can add components, add children GameObjects, instantiate prefabs and so on.

Then you need to define what happens when an object will be taken from the pool.

void OnTakeFromPool(GameObject pooledGameObject)
{
    pooledGameObject.SetActive(true);
    // reinitialize object, run animation and any other things
}

Then you need to define what to do when the object returns to the pool. Usually just deactivate an object.

void OnReturnedToPool(GameObject pooledGameObject)
{
    pooledGameObject.SetActive(false);
    // any other stuff here
}

In some cases that will be described a little bit later, objects need to be destroyed. So you need to define how to destroy.

void OnDestroyPoolObject(GameObject pooledGameObject)
{
    Destroy(pooledGameObject);
}

Ok, by now we have defined all necessary methods which the pool needs. So let’s create the pool instance!

var poolInstance = new ObjectPool<GameObject>(
    CreatePooledItem,
    OnTakeFromPool,
    OnReturnedToPool,
    OnDestroyPoolObject,
    collectionChecks,
    10,
    100);

You may notice the pool constructor needs three more parameters:

  • CollectionChecks — collection checks are performed when an instance is returned back to the pool. An exception will be thrown if the instance is already in the pool. Collection checks are only performed in the Editor.
  • DefaultCapacity — the default capacity the stack will be created with.
  • MaxPoolSize — the maximum size of the pool, if you request more objects from the pool it will create a new instance for you but when you return it to the pool it will be destroyed. That’s why we need the method that we defined later OnDestroyPoolObject.

Now you can use the pool instance as previous ones. The instance has the same two methods to retrieve object from the pool:

  • Public T Get()
  • Public PooledObject<T> Get(out T v)

and one that allows you to return an object to the pool:

  • Public void Release(T element)

Also there exist three more pool implementations:

  • LinkedPool<T0> — the difference between ObjectPool and LinkedPool that ObjectPool uses stack for storing object and LinkedPool uses list
  • GenericPool<T0> — static implementation of ObjectPool
  • UnsafeGenericPool<T0> — the same as GenericPool but without collection check

Conclusion

As you can see the new Pool API in Unity 2021 is easy to use and allows you to have full control of how and what is done at every step.

We hope this article will allow you to make what you want before you have any performance issues caused by objects instantiations and GC work and let you implement your next great ideas.

Machine Learning best practices: how to improve your company's...

Companies have been accumulating data and customer information for years, but extraction of value from large amounts of data still remains the greatest challenge. Artificial Intelligence (AI) and Machine Learning (ML) specifically allow you to get the most out of your dat...
April 3, 2021

Text mining 101: what it is and how it works for business

Text mining is essentially the automated process of deriving high-quality information from text. Let’s explore what business challenges can be addressed by this technology and what related applications WaveAccess has developed.
February 4, 2019

How to work with Open Source projects in Microsoft Azure. Part 1

How to optimize the cost of software development and delivery, where to start the transition to Open Source technologies and how to work with Open Source projects in the Microsoft Azure cloud? Find detailed instructions in our new blog posts series.
September 14, 2020

Related Services

Application Development
Mobile Applications Development
Support & Maintenance

How we process your personal data

When you submit the completed form, your personal data will be processed by WaveAccess USA. Due to our international presence, your data may be transferred and processed outside the country where you reside or are located. You have the right to withdraw your consent at any time.
Please read our Privacy Policy for more information.