오브젝트 풀링

정선호·2023년 5월 2일
0

Design Patterns

목록 보기
3/24

관련 영상
공식 문서

오브젝트 풀

  • '재사용' 가능한 객체들을 모아놓은 객체 풀 클래스를 정의하는 것
  • 장점) 메모리를 신경쓰지 않고 마음껏 객체를 생성, 삭제할 수 있다.
  • 단점) 객체 아무것도 사용하지 않아도 메모리를 차지하고 있는 상태가 됨.

오브젝트 풀의 구현 개념


  • 객체 풀 클래스에 들어가는 객체는 현재 자신이 사용중인지 아닌지 알 수 있는 방법을 제공해야 한다.
    1. 풀은 초기화될 때 사용할 객체들을 미리 생성하여 배열에 넣어두고 사용 안함 상태로 초기화 한다.
    2. 새로운 객체가 필요하면 풀에 요청한다.
    3. 풀은 사용 가능한 객체를 찾아 사용 중으로 초기화 한 뒤 리턴한다.
    4. 객체를 더 이상 사용하지 않는다면 사용 안 함 상태로 되돌린다.

오브젝트 풀을 사용해야 할 때

  • 객체를 빈번하게 생성/삭제 해야할 때
  • 객체들의 크기가 비슷할 때
  • 객체를 힙에 생성하기엔 느리거나 메모리 단편화가 우려될 때
  • DB 연결이나 네트워크 연결같이 객체 생성시 비용이 비쌀 경우 미리 생성해두고 재사용할 필요가 있을 때

Unity C#을 이용해 구현한 오브젝트 풀

  • 오브젝트
    • 오브젝트는 자신을 관리하는 오브젝트 풀을 알고 있어야 함
    • 오브젝트를 풀에서 재활성화 시 Start()함수는 다시 실행되지 않으므로 재활성화시마다 실행시킬 임의의 함수를 추가할 필요가 있다
  • 오브젝트 풀
    • 유니티가 제공하는 오브젝트풀은 오브젝트를 생성할 때, 오브젝트를 풀에서 꺼낼 때, 오브젝트를 다시 풀에 넣을 때, 오브젝트를 삭제할 때 어떻게 할 것인지에 대한 구현부를 직접 작성하여 생성자에 추가해주어야 한다
namespace ObjectPool
{
    // Values or methods that other can use
    public partial class EnemySpawner
    {
        
    }
    
    // Values or methods that other cannot use
    public partial class EnemySpawner
    {
    	// 유니티가 제공하는 오브젝트 인터페이스를 저장할 변수
        private IObjectPool<Enemy> _pool;

		// 관리할 게임오브젝트 프리팹
        [SerializeField] private GameObject enemyPrefab;
        private List<Transform> _spawnPos = new List<Transform>();
    }
    
    // body of MonoBehaviour
    public partial class EnemySpawner : MonoBehaviour
    {
        private void Awake()
        {
        	// 생성, 활성화, 비활성화, 삭제 시 호출할 함수와 풀의 최대 사이즈를 입력받음
            _pool = new ObjectPool<Enemy>(CreateEnemy, ActivateEnemy, DeActivateEnemy, OnDestroyEnemy, maxSize:20);
            
            foreach (Transform child in transform)
            {
                _spawnPos.Add(child);
            }
        }

        void Start()
        {
            StartCoroutine(_SpawnEnemy());
        }
    }
    
    // body of others
    public partial class EnemySpawner
    {
        private IEnumerator _SpawnEnemy()
        {
            while (true)
            {
                Vector3 pos = _spawnPos[Random.Range(0, _spawnPos.Count - 1)].position;
                Enemy enemy = _pool.Get();
                enemy.transform.position = pos;
                enemy.Init();

                yield return new WaitForSeconds(1f);
            }
        }

		// 풀이 비어있을 경우 오브젝트 인스턴스를 생성하여 반환하는 함수
        private Enemy CreateEnemy()
        {
            Enemy enemy = Instantiate(enemyPrefab).GetComponent<Enemy>();
            enemy.SetManagedPool(_pool);
            return enemy;
        }

		// 오브젝트 인스턴스를 풀에서 빼낼 때 실행하는 함수
        private void ActivateEnemy(Enemy enemy)
        {
            enemy.gameObject.SetActive(true);
        }
        
        // 오브젝트 인스턴스를 풀에 다시 넣을 때 실행하는 함수
        private void DeActivateEnemy(Enemy enemy)
        {
            enemy.gameObject.SetActive(false);
        }

		// 오브젝트 인스턴스를 삭제하는 함수
        private void OnDestroyEnemy(Enemy enemy)
        {
            Destroy(enemy.gameObject);
        }
    }
}
profile
학습한 내용을 빠르게 다시 찾기 위한 저장소

0개의 댓글