오브젝트 풀링이란?
오브젝트 풀링은 객체를 반복해서 생성하고 삭제하는 대신, 미리 만들어 놓고 재사용하는 디자인 패턴이다.
“필요할 때 꺼내 쓰고, 쓰지 않을 때는 돌려주는 대여 서비스라고 생각하면 쉽다!”
왜 오브젝트 풀링이 필요할까?
문제점
- 객체를 반복적으로 생성/삭제하면 성능이 저하되고 메모리 사용량이 증가한다.
- 특히 게임과 같이 실시간으로 빠른 응답 속도가 필요한 환경에서는 큰 문제가 될 수 있다.
오브젝트 풀링의 장점
- 성능 최적화 : 매번 객체를 생성하는 대신 재사용하니 CPU와 메모리 사용량 감소.
- 효율성 : 자주 사용되는 객체를 미리 생성해두면 더 빠르게 사용할 수 있다.
- 가비지 컬렉션 감소 : 객체 삭제를 최소화하므로 GC 호출 횟수가 줄어들어 끊김 현상 방지.
어떻게 사용하지?
1. 기본 오브젝트 풀 구현하기
아래 코드는 제네릭을 활용해서 다양한 타입의 객체를 관리할 수 있는 오브젝트 풀이다.
using System.Collections.Generic;
public class ObjectPool<T> where T : new()
{
private readonly Queue<T> pool = new Queue<T>();
// 풀에서 객체 가져오기
public T Get()
{
return pool.Count > 0 ? pool.Dequeue() : new T();
}
// 객체 반환
public void Return(T obj)
{
pool.Enqueue(obj);
}
}
// 사용 예제
public class Object
class Program
{
static void Main(string[] args)
{
ObjectPool<Object> objPool = new ObjectPool<Object>();
// 적 가져오기
Enemy obj1 = objPool.Get();
Enemy obj2 = objPool.Get();
// 적 반환하기
objPool.Return(obj1);
objPool.Return(obj2);
}
}
2. Unity에서 오브젝트 풀링 활용하기
우리가 사용할 Unity에서는 적이나 파티클 같은 오브젝트를 재사용할 때 활용할 수 있다.
오브젝트 풀 매니저
public class ObjectPool : MonoBehaviour
{
public GameObject prefab; // 미리 생성할 프리팹
public int poolSize = 10;
private Queue<GameObject> pool = new Queue<GameObject>();
private void Awake()
{
for (int i = 0; i < poolSize; i++)
{
GameObject obj = Instantiate(prefab);
obj.SetActive(false);
pool.Enqueue(obj);
}
}
public GameObject Get()
{
if (pool.Count > 0)
{
GameObject obj = pool.Dequeue();
obj.SetActive(true);
return obj;
}
// 풀 크기 초과하면 새로 생성함
GameObject newObj = Instantiate(prefab);
return newObj;
}
public void Return(GameObject obj)
{
obj.SetActive(false);
pool.Enqueue(obj);
}
}
사용 예제
public class EnemySpawner : MonoBehaviour
{
public ObjectPool pool; // 오브젝트 풀 참조
private void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
// 스페이스바를 누르면 적 생성
GameObject enemy = pool.Get();
enemy.transform.position = Vector3.zero; // 적 초기 위치 설정
}
}
private void OnEnemyDestroyed(GameObject enemy)
{
// 적이 파괴되면 반환
pool.Return(enemy);
}
}
어디에 사용하면 좋을까?
오브젝트 풀링은 생성/삭제가 자주 일어나는 객체를 관리할 때 특히 유용하다.
- 적 캐릭터, 총알, 파티클 : 게임에서 매우 자주 생성되는 오브젝트
- UI 요소 : 리스트나 카드처럼 반복적으로 추가/삭제되는 UI
- 네트워크 연결 : 웹 소켓이나 DB 연결
정리
- 오브젝트 풀링은 미리 객체를 만들어 두고 재사용하여 성능을 최적화 하는 방법
- Unity나 게임 개발에서는 필수적인 기법!
- 적용 포인트 : 성능 문제가 예상되는 곳에 우선 적용해보자.
“오브젝트 풀링을 잘 쓰면 성능 최적화는 물론이고 코드도 깔끔해진다! 꼭 한번 프로젝트에 적용해보기!”
+추가 : Unity 2021 이후 공식지원
Unity의 공식 오브젝트 풀링 시스템이 있다. ObjectPool<T> 클래스를 사용하면 오브젝트를 생성, 재사용, 반환하는 과정을 자동화할 수 있다. (Unity 2021 LTS 이상에서 사용 가능)
Unity ObjectPool 기본 사용법
// ...
using UnityEngine.Pool; // Unity의 Object Pool 네임스페이스
public class Bullet : MonoBehaviour
{
// 총알 동작 관련 로직
public void Shoot(Vector3 direction)
{
GetComponent<Rigidbody>().velocity = direction * 10f; // 총알 발사
}
}
public class BulletManager : MonoBehaviour
{
public GameObject bulletPrefab; // 총알 프리팹
private ObjectPool<GameObject> bulletPool;
private void Awake()
{
// 풀 초기화
bulletPool = new ObjectPool<GameObject>(
createFunc: () => Instantiate(bulletPrefab), // 객체 생성 로직
actionOnGet: obj => obj.SetActive(true), // 객체 사용 시 동작
actionOnRelease: obj => obj.SetActive(false),// 반환 시 동작
actionOnDestroy: Destroy, // 풀 크기 초과 시 삭제
maxSize: 20 // 최대 풀 크기
);
}
public void ShootBullet(Vector3 position, Vector3 direction)
{
GameObject bullet = bulletPool.Get(); // 풀에서 객체 가져오기
bullet.transform.position = position;
bullet.GetComponent<Bullet>().Shoot(direction);
// 일정 시간 후 풀로 반환
StartCoroutine(ReturnBulletAfterTime(bullet, 2f));
}
private IEnumerator ReturnBulletAfterTime(GameObject bullet, float time)
{
yield return new WaitForSeconds(time);
bulletPool.Release(bullet); // 객체 반환
}
}
참조
오브젝트 풀링을 사용하여 Unity에서 C# 스크립트 성능 향상하기
'Develop > Unity' 카테고리의 다른 글
싱글톤(Singleton) 패턴에 대해서.Araboza (0) | 2025.02.03 |
---|