본문 바로가기
개발/게임 디자인 패턴

게임 디자인 패턴 14. 객체 풀 패턴 (Object Pool Pattern)

by 석시 2023. 11. 9.



객체 풀 (오브젝트 풀) 역시 상당히 자주 나와 익숙한 패턴일 것이다.

필자도 객체 풀을 한 번 정리한 적이 있었다.

Unity 오브젝트 풀
오브젝트 풀을 쓰는 이유오브젝트 풀 생성풀링용 함수 작성 오브젝트 풀을 쓰는 이유 유니티에서는 프리팹을 만들어 개체를 생성할 때 생성함수 Instantiate()와 삭제함수 Destroy()를 제공해준다. 하지만 이 두가지의 함수를 너무 자주 사용하게 되면 물리적인 메모리 상에서 파편화된 메모리 (찌꺼기 메모리)가 계속해서 발생하게 되면서 성능에 악영향을 줄 수 있다. 이러한 문제를 해결하기 위해 오브젝트 풀링 (Object Pooling)이라는 것을 사용한다. 직접 한 번 만들어보는 시간을 가져보자. 나는 골드메탈님의 유튜브 강좌를 참고하여 몬스터를 소환하는 오브젝트 풀을 제작해보았다. 오브젝트 풀링🏊으로 소환하기 [유니티 뱀서라이크 06]플레이어 주변에 수많은 적을 소환하는, 뱀서라이크의 묘미를 직접..
https://seoksii.tistory.com/40

이번에는 객체 풀의 주의사항과 디자인 요소에 대해 집중적으로 알아보겠다.


객체 풀 사용 시 주의점

객체 풀에서 가장 중요한 요소 중 하나는 풀의 크기이다.

즉, 몇 개의 오브젝트를 미리 생성해놓고 있을 것이냐가 중요 포인트가 되겠다.

객체 풀의 크기가 너무 작다면

객체 풀의 크기가 너무 작다면, 객체 풀의 모든 객체가 사용 중이어서 재사용할 객체를 반환받지 못하는 경우가 있을 것이다.

이 경우 동작 방식을 다음과 같이 정할 수 있다.

  1. 그냥 객체를 생성하지 않는다 : 파티클 시스템 같은 곳에서는 한 두개의 파티클이 무시된다 하더라도 티가 별로 나지 않기 때문에 가능한 짓이다.
  1. 기존 객체를 강제로 제거한다 : 사운드를 풀로 만들어 관리할 때, 제일 작은 소리의 객체를 새로운 사운드로 만든다면 이 역시 별로 티가 나지 않을 것이다.
  1. 풀의 크기를 늘린다 : 제일 많이 사용하는 방식 같다. 런타임에 풀을 늘리거나 보조 풀을 만드는 방식인데, 이러면 또 추가로 사용한 메모리를 더 쓰지 않을 때 풀의 크기를 다시 원래대로 복구할 것인지 아닌지 정할 수도 있다.

객체 풀의 크기가 너무 크다면

이건 이거대로 문제인게, 사용하지 않는데 메모리를 차지하고 있는 객체가 너무나도 많아지는 것이다.

놀고 있는 객체들에서도 문제가 발생할 수 있다.

그 외 주의사항

  1. 객체를 위한 메모리 크기는 고정되어 있다 : 배열 기준 제일 큰 객체를 기준으로 풀 한 칸 한 칸의 크기가 결정된다. 풀에 들어 있는 객체 간 크기가 많이 차이가 난다면? 공간 낭비가 무지막지해지는 것이다.
  1. 재사용되는 객체는 저절로 초기화되지 않는다 : 내가 일일히 초기화를 해줘야 한다. 이 때 완전하게 초기화를 해주지 않는다면?
  1. 비활성화된 객체가 다른 객체를 참조하고 있을 수 있다 : 이렇게 되면 GC가 참조된 객체의 메모리를 회수할 수가 없게 된다. 따라서 풀에 있는 객체를 사용하지 않을 때 다른 객체를 참조하는 부분을 반드시 정리해줘야 한다.


디자인 요소

  1. 풀이 객체와 커플링되는가?

커플링되면 장점이 있다. 객체를 풀을 통해서만 생성할 수 있도록 강제할 수 있다는 것이다.

사용 중인지 아닌지도 상태를 따로 두지 않고도 관리가 가능하도록 만들 수 있다.

반대로 풀과 객체를 디커플링 시켜놓으면, 어떤 객체든 풀에 넣을 수 있게 되지만, 사용 중인지 아닌지 상태를 외부에서 따로 관리해줘야 한다.

  1. 풀에서 꺼낸 객체를 어디서 초기화시켜주는가?

객체를 풀 안에서 초기화한다면 풀 입장에서 객체를 완전히 캡슐화할 수 있지만, 풀과 객체가 커플링이 되어버린다.

반대로 객체를 밖에서 초기화한다면 풀의 인터페이스가 단순해지지만, 객체 생성이 실패했을 때 초기화할 경우 버그가 생길 수 있다는 점이 있다.


참고

윈도우에서 16kB 이하 메모리를 많이 할당한다면 직접 만든 메모리 풀보다 LFH(low-fragmentation heap)를 썼을 때 더 효과가 좋은 경우가 많다고 한다.

낮은 조각화 힙 - Win32 apps
힙 조각화는 사용 가능한 메모리가 인접하지 않은 작은 블록으로 나눌 때 발생합니다. LFH(하위 조각화 힙)는 힙 조각화를 줄이는 데 도움이 됩니다.
https://learn.microsoft.com/ko-kr/windows/win32/memory/low-fragmentation-heap?redirectedfrom=MSDN

객체 풀을 보통은 리스트나 배열로 구현할텐데 빈 칸 리스트 (Free List) 기법을 이용해 만들어볼 수 있다.

풀에 있는 객체를 리스트 노드처럼 만들어서 객체들을 연결해주어 연결 리스트처럼 만들고, 풀에서 사용 가능한 객체를 얻어올 때 이 연결된 객체들 중 가장 첫번째 객체를 가져오면 된다.

수정 및 삽입이 O(1)에 이루어지는 아름다운 풀이 완성되는 것이다.


Uploaded by N2T