주녘공부일지

[Unity] 오브젝트 풀링 (Object Pooling) 본문

GameDevelopment/[Unity] Class, Pattern

[Unity] 오브젝트 풀링 (Object Pooling)

주녘 2022. 2. 1. 17:55

Object Pooling : 오브젝트를 재활용하기 위한 디자인 패턴 ( 최적화 )

 

빈번히 생성, 파괴되는 오브젝트들을 풀에 모아서 미리 생성해놓고 활성화 / 비활성화로 관리하며 재사용

 

- 런타임 중에 수십개의 다른 오브젝트를 생성하고 파괴하는 것은 성능적으로 굉장히 많은 공간을 차지하기 때문에, 미리 생성함으로써 런타임에서의 불필요한 메모리 낭비를 최소화하지만, Loading 시간이 소요됨 

 

- C++은 힙에 메모리 공간을 할당하고 원하는 시점에 삭제할 수 있지만, ( new, delete )  C#은 사용하지 않는 메모리가 생기면 가비지 컬렉트(GC)가 일정 주기마다 메모리를 정리하기 때문에 GC의 실행 시점을 제어하기 위해서도 사용

 

- 만약, 풀 안에 오브젝트를 가져오려고 할 때, 모든 오브젝트가 사용중이라면 오브젝트를 생성하고 다시 넣으려고 할 때 풀 안의 공간이 차있다면 파괴하여 예외처리를 해놓는 것이 좋지만, 이런 일이 일어난다면 가비지 컬렉트가 실행되어 버림

 

- pool의 오브젝트 갯수는 너무 작으면 시점 제어를 못하여 랙을 유발시킬 수 있게 되고, 너무 크다면 메모리를 낭비하게 되므로 적당한 개수를 가져야 함

 

+ 가비지 컬렉터 (GC) : 쌓인 사용하지 않는 메모리를 비우는 기술

 ( 닷넷프레임워크에서 제공하는 자동메모리관리시스템 )

 

+ 사용하지 않는 메모리 : Destroy된 객체, 사용이 끝난 지역 변수, 등

 

대표적 사용 예시 : 총알, 등

 

 

사용 예제

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ObjectManager : MonoBehaviour
{
    [SerializeField] GameObject bulletPrefab;
    GameObject[] bullet;
    
    void Awake()
    {
        bullet = new GameObject[100];
        Generate();
    }
    
    void Generate()
    {
        for (int index = 0; index < bullet.Length; index++)
        {
            bullet[index] = Instantiate(bulletPrefab);
            bullet[index].SetActive(false);
        }
    }

    public GameObject MakeObj(string type)
    {
        switch (type)
        {
            case "Bullet":
                targetPool = bullet;
                break;
            default:
                Debug.Log("MakeObj() switch not find");
                break;
        }

        for (int index = 0; index < targetPool.Length; index++)
        {
            if (!targetPool[index].activeSelf)
            {
                targetPool[index].SetActive(true);
                return targetPool[index];
            }
        }

        Debug.Log("MakeObj() return null");
        return null;
    }

    public GameObject[] GetPool(string type)
    {
        switch (type)
        {
            case "Bullet":
                targetPool = bullet;
                break;
            default:
                Debug.Log("GetPool() switch not find");
                break;
        }
        
        return targetPool;
    }
}