[Unity] 오브젝트 풀 패턴(Object Pool Pattern): 효율적인 오브젝트 재사용 전략

2024. 12. 2. 16:31·👻 Unity

 

🗨 개인적인 공부 기록용으로 정리한 내용입니다. 잘못된 내용에 대한 피드백은 언제나 감사합니다 :)

 

 

 

⭐ 오브젝트 풀은 반복적으로 생성/소멸되는 객체(`오브젝트`)를 풀(`Pool`)에 미리 생성 및 저장해 두고 필요시 꺼내 쓰고, 사용이 끝나면 다시 반환하여 관리하는 디자인 패턴이다.

 

 

 

게임 개발을 하다 보면 특정 객체(`Object`)는 생성하고 소멸시키는 작업을 자주 해야 하는 상황이 생긴다.

특히 총알, 적(Enemy), 파티클 이펙트처럼 짧은 시간에 생성과 소멸이 반복되는 오브젝트들은 성능 저하의 주요 원인이 된다.

이때, 생성/소멸의 부담을 크게 줄여 성능을 최적화시키는 패턴이 바로 오브젝트 풀(Object Pool) 패턴이다.

 

 

 

 

 

📌 오브젝트 풀이란?

  • 오브젝트를 미리 생성하여 풀(`Pool`)에 저장해 두고, 필요하면 풀에서 꺼내 쓰고, 사용이 끝나면 다시 풀로 돌려보낸다.
  • 많은 수의 오브젝트를 생성하고 파괴할 때 CPU의 부담을 줄이는 최적화 기법이다.
  • 로딩 시간에 오브젝트를 미리 만들어 풀에 담아두고, 런타임에는 사용하기만 하는 식으로 구현한다.

화면에서 소멸되어야하는 총알이나 몬스터는 파괴 대신 오브젝트 풀로 반환 및 비활성화 한다.

 

 

 

📌 오브젝트 풀을 왜 사용하는가?

오브젝트 풀은 주로 성능과 메모리 관리 최적화를 위해 사용한다.

특히 Unity에서 오브젝트 풀을 FPS, 슈팅 게임, 그리고 다양한 장르에서 성능을 최적화하는 필수적인 도구로 쓰인다.

  1. 성능 최적화
    • 객체를 자주 생성하고 파괴하는 작업은 메모리 할당 및 해제에 따른 오버헤드가 크다. 이는 성능 저하의 주요 원인이다.
    • 오브젝트 풀을 사용하면 객체를 재사용함으로써 성능을 개선할 수 있다.
  2. 가비지 컬렉션(GC) 부담 감소
    • 빈번한 메모리 할당 및 해제는 가비지 컬렉션을 유발하여 프레임 드랍이 발생할 수 있다.
    • 오브젝트 풀로 가비지 컬렉션 급증으로 인해 발생할 수 있는 밑줄 끊김 현상(Hiccup, GC spike)을 예방할 수 있다.
  3. 일정한 메모리 사용
    • 한 번에 생성할 수 있는 오브젝트의 개수를 제한할 수 있다. 
    • (반대로, 생성하고 사용하지 않을 경우 메모리 낭비가 되는 단점이 있다.)

 

 

 

 

 

📌 오브젝트 풀의 구조와 구현

오브젝트 풀의 기본 구성 요소는 Pool, Pool Manager(관리자), Client(사용자)로 나눌 수 있다.

  1. Pool
    • 미리 생성된 객체를 저장
    • 일반적으로 `List`, `Queue`, 혹은 `Stack` 자료 구조를 사용한다. (아래 예시코드는 `Stack` 사용)
  2. Pool Manager(관리자)
    • Pool에서 객체를 가져오거나 반환하는 역할 담당
    • 필요한 경우 새로운 객체를 생성하거나 Pool에 반환
  3. Client(사용자)
    • 오브젝트 풀에 객체를 요청해서 사용 후  반환

 

 

 

🔖 Object Pool 

Unity에서 사용하는 기본적인 오브젝트 풀(Object Pool)의 구현 예시이다.

 

 

예시 코드 | 오브젝트 풀(Object Pool)

 

🌞 유니티에서 배포한 코드입니다.

/* 오브젝트 풀 */
public class ObjectPool : MonoBehaviour
{
    [SerializeField] private uint initPoolSize; // 풀(Pool) Size 설정
    [SerializeField] private PooledObject objectToPool; 
    
    private Stack<PooledObject> stack;  // 풀링된 오브젝트들을 담는 스택 
    private void Start()
    {
        SetupPool();    // 게임 플레이 중 한 번 실행
    }
    /* 풀 생성 */
    private void SetupPool()
    {
        stack = new Stack<PooledObject>();
        PooledObject instance = null;
        for (int i = 0; i < initPoolSize; i++)  // 위에서 정한 initPoolSize만큼 생성
        {
            instance = Instantiate(objectToPool);
            instance.Pool = this;
            instance.gameObject.SetActive(false);   // 비활성화 🔴 (준비 단계이기 때문에 비활성 해놓기)
            stack.Push(instance);
        }
    }

    /* 풀에서 첫 번째 액티브 게임 오브젝트를 반환 */
    public PooledObject GetPooledObject()
    {
        /* 풀이 비어있으면(=더이상 꺼낼 오브젝트가 없으면), 새로운 PooledObjects를 인스턴스화*/
        if (stack.Count == 0)
        {
            PooledObject newInstance = Instantiate(objectToPool);
            newInstance.Pool = this;
            return newInstance;     // 일회성 인스턴스
        }
        /* 그렇지 않으면, 풀에서 다음 요소(인스턴스)를 꺼냄 */
        PooledObject nextInstance = stack.Pop();
        nextInstance.gameObject.SetActive(true);    // 활성화 🔵
        return nextInstance;
    }
    /* 사용이 끝난 오브젝트를 풀에 반환할 때 호출 */
    public void ReturnToPool(PooledObject pooledObject)
    {
        stack.Push(pooledObject);
        pooledObject.gameObject.SetActive(false);   // 비활성화 🔴
    }
}

 

 

풀링된 오브젝트(Client)는 ObjectPool.cs을 참조하기 위해 아래 PooledObject 컴포넌트를 가진다.

/* Object Pool의 관리 대상인 오브젝트 */
public class PooledObject : MonoBehaviour
{
    private ObjectPool pool;
    public ObjectPool Pool { get => pool; set => pool = value; }
    /* 게임 오브젝트가 비활성화되고 풀로 반환하는 함수 */
    public void Release()
    {
        pool.ReturnToPool(this);
    }
}

 

 

 

 

 

🔖 UnityEngine.Pool (유니티 API)

유니티 2021 버전부터 자체적으로 오브젝트 풀(스택 기반) API을 제공한다. 🔗 Unity Doc

 

UnityEngine.Pool 은 유니티에서 제공하는 기본 Object Pooling 라이브러리다.

`using UnityEngine.Pool`로 사용이 가능하며, 기본적인 인터페이스가 구현되어 있다.

오브젝트 풀을 처음부터 만들 필요가 없어 시간을 단축할 수 있다.

 

 

🧩 제공하는 기능

  • 오브젝트 생성하여, `Pool`을 채운다.
  • `Pool`에서 가져오기
  • `Pool`로 반환하기
  • 풀링 된 오브젝트 파괴하기
    • 주로 최대한도에 도달한 경우 사용한다.

 

 

예시 코드 | UnityEngine.Pool API 사용

using UnityEngine.Pool;
public class RevisedGun : MonoBehaviour
{
 …
 // Unity 2021 이상 버전에서 사용 가능한 스택 기반 ObjectPool
 private IObjectPool<RevisedProjectile> objectPool;
    // 이미 풀에 있는 기존 항목을 반환하려 할 때 예외를 반환
    [SerializeField] private bool collectionCheck = true;
    // 풀의 용량과 최대 크기를 제어하는 추가 옵션
    [SerializeField] private int defaultCapacity = 20;
    [SerializeField] private int maxSize = 100;
    private void Awake()
    {
        objectPool = new ObjectPool<RevisedProjectile>(CreateProjecti
       le,
        OnGetFromPool, OnReleaseToPool, OnDestroyPooledObject,
        collectionCheck, defaultCapacity, maxSize);
    }
    // 오브젝트 풀을 채울 항목을 만들 때 호출됨
    private RevisedProjectile CreateProjectile()
    {
        RevisedProjectile projectileInstance =
       Instantiate(projectilePrefab);
        projectileInstance.ObjectPool = objectPool;
        return projectileInstance;
    }
    // 오브젝트 풀로 항목을 반환할 때 호출됨
    private void OnReleaseToPool(RevisedProjectile pooledObject)
    {
        pooledObject.gameObject.SetActive(false);
    }
    // 오브젝트 풀에서 다음 항목을 검색할 때 호출됨
    private void OnGetFromPool(RevisedProjectile pooledObject)
    {
        pooledObject.gameObject.SetActive(true);
    }
    // 풀링된 항목의 최대 개수를 초과할 때 호출됨(풀링된 오브젝트 파괴)
    private void OnDestroyPooledObject(RevisedProjectile pooledObject)
    {
        Destroy(pooledObject.gameObject);
    }
    private void FixedUpdate()
    {
 …
 }
}

 

 

 

 

 

📌 오브젝트 풀의 단점

오브젝트 풀의 문제점으로는 메모리 낭비 가능성이 있다.

  • 필요 이상의 객체를 미리 생성하면 메모리가 낭비될 수 있다.
  • 사용되지 않는 객체도 메모리를 점유한다.

Thread-Safe 하지 않다.

  • 멀티스레드에서 사용하기 위해선 동기작업이 필요하다.

 

 

 

 


참고

 

게임 프로그래밍 패턴으로 코딩 스킬 업그레이드

 

게임 프로그래밍 패턴으로 코딩 스킬 업그레이드

새로운 전자책에서는 잘 알려진 디자인 패턴과 함께 실제 Unity 프로젝트에서 활용할 수 있는 실용적인 예제를 소개합니다.

unity.com

 

Object pool pattern - Wikipedia

 

Object pool pattern - Wikipedia

From Wikipedia, the free encyclopedia Software creational design pattern The object pool pattern is a software creational design pattern that uses a set of initialized objects kept ready to use – a "pool" – rather than allocating and destroying them on

en.wikipedia.org

 

오브젝트 풀링을 사용하여 Unity에서 C# 스크립트 성능 향상하기

 

오브젝트 풀링을 사용하여 Unity에서 C# 스크립트 성능 향상하기

이 페이지에서는 오브젝트 풀링과 이를 통해 게임 성능을 개선하는 방법에 대해 설명합니다. 여기에는 프로젝트에 Unity의 빌트인 오브젝트 풀링 시스템을 구현하는 방법에 대한 예제가 포함되

unity.com

 

 

저작자표시 비영리 변경금지 (새창열림)

'👻 Unity' 카테고리의 다른 글

[Unity] 싱글톤 패턴(Singleton Pattern): 오직 하나뿐인 객체  (0) 2024.11.27
[Unity] 유니티 설치 실패: Validation Failed 원인 및 해결 방법  (0) 2024.08.20
'👻 Unity' 카테고리의 다른 글
  • [Unity] 싱글톤 패턴(Singleton Pattern): 오직 하나뿐인 객체
  • [Unity] 유니티 설치 실패: Validation Failed 원인 및 해결 방법
Mojing_
Mojing_
매일 매일 경험치를 쌓는 모징이의 개발 블로그입니다 :) This is Mojing’s Dev Blog where she gain experience points every day. :)
  • Mojing_
    모징이의 개발 경험치
    Mojing_
  • 전체
    오늘
    어제
    • 분류 전체보기 (143)
      • 👻 Unity (5)
        • 🔧 기능 구현 (0)
        • 💡 유니티 팁 (0)
        • 📘 Unity 노트 (2)
      • 💻 Programming (14)
        • C (3)
        • C++ (9)
        • C# (0)
        • Swift (2)
      • 💾 Computer Science (16)
        • Algorithm (9)
        • Software Engineering (7)
      • 🐸 Problem Solving (108)
        • Programmers (41)
        • BOJ (67)
      • 🔋 ETC (0)
      • 💡 Quest Log (0)
  • 인기 글

  • 공지사항

  • 태그

    dynamic programming
    sort
    탐색
    C++
    algorithm
    티스토리챌린지
    Unity
    오블완
    프로그래머스
    backtracking
    programmers
    Problem Solving
    DFS/BFS
    CS
    BOJ
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
Mojing_
[Unity] 오브젝트 풀 패턴(Object Pool Pattern): 효율적인 오브젝트 재사용 전략
상단으로

티스토리툴바