Just start typing...
Technologies

New Pooling API in Unity 2021

Published January 31, 2022
Let us tell you more about our projects
Start here

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.

 

Let us tell you more about our projects

 Start here

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.

Energy Management System for Mata Energy

The solution is aimed to facilitate sector-coupled energy supply, improving its efficiency. For the client we provided a consulting session, and developed an MVP.

WaveAccess named among Clutch Global Leaders 2023

We're thrilled to announce that WaveAccess has been recognized as a winner of the Clutch Global Awards 2023 in the IoT, Cognitive Computing, and Microsoft Dynamics CRM categories. Clutch Global leaders are selected based on the platform’s strict methodology, emphasizing industry expertise and the ability to deliver results.

myQuiz converts ‘social distancing’ into ‘distance socializing’

March, 2020. The WHO offered to use the term ‘physical distancing’ instead of ‘social distancing’, because for those who stay at home social relations are more important than ever. In this article, we’d like to talk about a couple of stories where people who communicate and have fun using myQuiz, our own web product. In 2020, this platform helped to engage isolated audiences in activities and events that previously were not even possible.

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.