목차
오브젝트 풀 패턴
오브젝트 풀의 가장 중요한 점은, 메모리를 사용하여 로드된 오브젝트를 저장함으로써, 로드와 디스트로이를 직접적으로 하지 않는다는 점입니다.
유니티에선 생성과 디스트로이에 많은 성능이 필요합니다. 그에 따라 프레임이 끊길 수도 있죠. 그걸 방지하기 위해, 메모리를 사용하여 해결하는 방법이 바로 오브젝트 풀링 패턴입니다.
오브젝트 풀은 특정 요청을 받아서 오브젝트를 생성합니다. 이 때, 만약 풀링된 오브젝트가 있다면, 직접적으로 생성되지 않고 저장된 오브젝트를 반환합니다. (저장되어있지 않다면, 생성합니다.)
오브젝트 풀의 장단점
장점
•
예측할 수 있는 메모리 사용 : 오브젝트 풀을 사용하여, 특정한 종류의 객체 인스턴스를 특정한 양만큼 유지하도록 예측 가능한 방식으로 메모리 일부를 할당할 있습니다.
ㄴ 간단하게 말해서 A라는 오브젝트를 50개로 설정한 풀링 패턴이라면, 이 오브젝트 풀링패턴은 최대 50개의 A메로리를 사용한다는 얘기입니다.
•
성능 향상 : 메모리를 사용하여 객체를 생성하고 삭제하는 비용이 없습니다.
단점 :
•
예측 불가능한 객체 상태 : 잘못 처리한 경우 객체가 초기 상태 대신 현재 상태로 풀에 되돌아올 수 있습니다.
ㄴ 위 문제는 정말 많이 발생하는 문제입니다. 해결법으로는 생성시에 초기화를 꼭 해주고 생성해야되는 방법밖에 없습니다. 개인적으로 초기화가 오브젝트 풀링패턴에서 가장 중요하다고 생각됩니다.
오브젝트 풀 유니티!
오브젝트 풀은 유니티 2021 버전 이상에서 제공됩니다! (드디어!!)
public class PoolExample : MonoBehaviour
{
public enum PoolType
{
Stack,
LinkedList
}
public PoolType poolType;
// Collection checks will throw errors if we try to release an item that is already in the pool.
public bool collectionChecks = true;
public int maxPoolSize = 10;
IObjectPool<ParticleSystem> m_Pool;
public IObjectPool<ParticleSystem> Pool
{
get
{
if (m_Pool == null)
{
if (poolType == PoolType.Stack)
m_Pool = new ObjectPool<ParticleSystem>(CreatePooledItem, OnTakeFromPool, OnReturnedToPool, OnDestroyPoolObject, collectionChecks, 10, maxPoolSize);
else
m_Pool = new LinkedPool<ParticleSystem>(CreatePooledItem, OnTakeFromPool, OnReturnedToPool, OnDestroyPoolObject, collectionChecks, maxPoolSize);
}
return m_Pool;
}
}
ParticleSystem CreatePooledItem()
{
var go = new GameObject("Pooled Particle System");
var ps = go.AddComponent<ParticleSystem>();
ps.Stop(true, ParticleSystemStopBehavior.StopEmittingAndClear);
var main = ps.main;
main.duration = 1;
main.startLifetime = 1;
main.loop = false;
// This is used to return ParticleSystems to the pool when they have stopped.
var returnToPool = go.AddComponent<ReturnToPool>();
returnToPool.pool = Pool;
return ps;
}
// Called when an item is returned to the pool using Release
void OnReturnedToPool(ParticleSystem system)
{
system.gameObject.SetActive(false);
}
// Called when an item is taken from the pool using Get
void OnTakeFromPool(ParticleSystem system)
{
system.gameObject.SetActive(true);
}
// If the pool capacity is reached then any items returned will be destroyed.
// We can control what the destroy behavior does, here we destroy the GameObject.
void OnDestroyPoolObject(ParticleSystem system)
{
Destroy(system.gameObject);
}
void OnGUI()
{
GUILayout.Label("Pool size: " + Pool.CountInactive);
if (GUILayout.Button("Create Particles"))
{
var amount = Random.Range(1, 10);
for (int i = 0; i < amount; ++i)
{
var ps = Pool.Get();
ps.transform.position = Random.insideUnitSphere * 10;
ps.Play();
}
}
}
}
C#
복사
위 코드는 유니티 2021.3의 가장 최신 레퍼런스 오브젝트 풀링 패턴입니다.
m_Pool = new ObjectPool<ParticleSystem>(CreatePooledItem, OnTakeFromPool, OnReturnedToPool, OnDestroyPoolObject, collectionChecks, 10, maxPoolSize);
C#
복사
가장 중요한 점은 위의 오브젝트 풀링 선언 문입니다.
CreatePooledItem : 오브젝트를 생성하는 함수입니다.
OnTakeFromPool : 오브젝트를 풀링 패턴에서 갖고올 때, 발동되는 함수입니다.
OnReturnedToPool : 오브젝트를 풀링 패턴에 반환할 때, 발동되는 함수입니다.
OnDestroyPoolObject : 오브젝트 풀링의 각 요소를 파괴할 때, 발동되는 함수입니다.
collectionChecks : 오브젝트 풀링 사용 여부입니다.
DefaultCapcity 10 : 오브젝트 풀링의 리스트에 처음으로 생성될 Capacity입니다. List의 그것과 동일!
maxPoolSize : 오브젝트 풀의 최대 스택 갯수입니다.