Question : 오브젝트 풀링이란 무엇인가요?
Answer : 오브젝트 풀링은 게임 개발에서 성능을 높이기 위해 사용하는 기법입니다.
게임에서 필히 오브젝트를 생성과 파괴를 하게 되는데요.
생성시 메모리를 할당하는 과정이 있고 파괴시 GC ( 가비지 콜렉터 )가 수거하는 과정에서 프레임 드랍이 생기게 됩니다.
GC 사용은 무겁기 때문에 GC 가 자주 수거해야 하는 상황이 오면 그만큼 프레임 드랍이 자주 발생합니다.
이러한 문제점을 해결하기 위해 오브젝트 풀링 기법을 사용합니다.
오브젝트 풀링은 자주 사용하게 될 오브젝트를 생성할 메모리를 미리 배열이나 리스트 등에 할당해놓고
필요할 때마다 꺼내서 쓰고 필요 없어지면 파괴가 아니라 비활성화해서 배열이나 리스트 등에 다시 넣는 기법입니다.
Question : 그럼 오브젝트 풀링을 사용할 때의 단점이나 주의할 점은 무엇인가요?
Answer :
오브젝트 풀링의 단점으로는 미리 메모리 공간을 할당하기 때문에 풀링 기법으로 할당해놓고 자주 사용하지 않는다면 메모리 공간을 낭비하게 됩니다. 자주 사용할 오브젝트가 아닌데도 풀링 기법으로 할당 해놓으면 역시 메모리를 낭비하게 됩니다.
<보충 설명>
오브젝트 풀링은 미리 객체를 생성해두기 때문에 메모리 사용량이 증가할수 있다.
또한 , 풀의 크기를 잘못 설정하면 메모리 낭비나 부족 현상이 발생할수 있다.
그리고 풀링된 오브젝트를 재사용할 때 초기화가 제대로 되지 않으면 예기치 않은 동작
( 이전 상태가 남는 버그 )이 생길 수 있다.
마지막으로 풀을 관리하는 코드 복잡도가 올라가는 것도 단점이다.
Question : 그렇다면 풀링된 오브젝트를 재사용할 때 상태가 초기화되지 않아 문제가 생긴다고 했는데요.
이런 문제를 방지하기 위해 개발자가 취할 수 있는 방법에는 어떤 게 있을까요?
Answer :
오브젝트 풀에서 객체를 가져올 때 항상 초기화하도록 명시적으로 코드를 작성해야 합니다.
<보충 설명>
풀에서 오브젝트를 꺼낼 때 항상 초기화 메서드를 호출하도록 명시적으로 관리한다.
OnSpawn() 이나 ResetState() 같은 메서드를 정의해
위치, 속도, 체력 등 이전 프레임의 데이터가 남지 않게 초기화한다.
풀에 반환할 때 ( OnDespawn )도 정리 작업을 해두면 다음 사용 시 안전하다.
Question : 좋습니다. 그럼 오브젝트 풀링을 Unity 에서 직접 구현한다면,
어떤 자료구조를 사용하는 것이 일반적이며 , 그 이유는 무엇인가요?
Answer :
일반적으로는 List 제네릭을 사용합니다.
물론 상황에 따라 Queue 나 Array 등도 사용할 수 있습니다.
Array 사용시 풀에서 꺼내는 객체의 수가 Array 크기보다 클 때에는 문제가 발생하므로
일반적으로는 사용이 유연하게 크기를 조절할 수 있는 List 가 좋습니다.
<보충 설명>
보통 List<GameObject> 나 Queue<GameObject>를 많이 쓴다.
List 는 유연하게 크기를 조절할 수 있고 , 인덱스로 접근이 빠르다.
Queue 는 사용 / 반환 순서가 명확할 때 ( 총알처럼 FIFO 구조 )에 적합하다.
Question : 좋아요. 그럼 Unity 의 Instantiate() 와 SetActive(true)의 차이 관점에서,
오브젝트 풀링이 성능상 이점을 갖는 이유를 엔진 내부 동작 측면에서 설명해주실 수 있을까요?
Answer :
Instantiate 할때 메모리를 할당해야 해서 성능 문제가 있고
SetActive(true) 는 이미 메모리에 할당된 객체를 활성화 하는 방법이라 프레임 드랍이 생기지 않습니다.
<보충 설명>
Instantiate 는 C# 과 Unity엔진 (C++) 영역 모두에서 새로운 GameObject 를 생성하고,
컴포넌트 초기화 Awake / Start 호출, 메모리 할당 등이 일어나기 때문에 매우 비싸다.
반면 SetActive(true)는 이미 존재하는 객체의 활성화 플래그만 변경하기 때문에
메모리 재할당이나 컴포넌트 재생성 없이 빠르게 처리된다.
그래서 오브젝트 풀링은 Instantiate() 호출 빈도를 줄여 GC와 프레임 드랍을 방지한다.
Question : 그렇다면 SetActive(true) 로 활성화할 때,
Unity의 생명주기 (Life Cycle) 중 어떤 콜백들이 다시 호출되나요?
Answer : 음.. 그 부분은 잘 모르겠습니다.
<보충 설명>
풀링된 객체가 다시 SetActive(true) 될 때는 Awake나 Start는 다시 호출되지 않고,
OnEnable() 이 다시 호출된다.
그래서 풀링된 오브젝트를 재사용할 때는 초기화 코드를 보통 OnEnable() 에 두는 편이다.
Question :
좋습니다. 그렇다면 OnEnable() 대신 초기화 메서드를 직접 호출하는 구조를 선호하는 개발자들도 있습니다.
이렇게 직접 초기화 메서드를 만드는 이유는 무엇일까요?
Answer : 코드 간결화를 위해서 그런 것 같습니다.
<보충 설명>
코드 간결화는 방향성이 완전히 틀린 것은 아니지만, 실제 이유는 조금 다르다.
코드 간결화 보다는 초기화 시점의 제어권을 개발자가 가지기 위해서가 더 정확한 이유이다.
OnEnable() 은 Unity 엔진이 오브젝트 활성화 시점을 감지해서 자동으로 호출하는 콜백이다.
"언제 실행될지 완전히 예측하기 어렵고 의도하지 않은 순서로 실행될 수 있다"
는 뜻이다.
그래서 실무에서는 직접 초기화 메서드 (Initialize() 나 ResetState() 등)를 만들어
풀에서 오브젝트를 꺼낼 때 명시적으로 호출한다.
Question : 좋습니다.
그러면 오브젝트 풀링을 너무 많이 사용했을 때 발생할 수 있는 엔진 레벨 부하나 병목 현상에는 어떤 것이 있을까요?
Answer : 오브젝트를 자주 사용해야 하는데 풀의 크기를 너무 낮게 잡으면 공간을 늘리는데 많은 연산량을 요구하므로 프레임 드랍이나 병목 현상이 발생할 수 있습니다.
<보충 설명>
유사 정답이다.
질문의 초점은 풀링 시스템이 너무 많을 때 발생하는 엔진 부하였다.
풀의 크기 조절보다는 풀 자체가 너무 많은 때 Unity 엔진 내부적으로 생길 수 있는 성능 병목을 묻는 질문이다.
오브젝트 풀리을 지나치게 남용하면 다음과 같은 문제가 발생한다.
1. 활성 / 비활성 오브젝트 수가 너무 많은 때 Scene 관리 부하
2. Update , Collider , Renderer 등 컴포넌트 관리 오버헤드
3. GC 관리 비용 증가
4. 풀 관리 스크립트의 연산 오버헤드
'📖TIL' 카테고리의 다른 글
| 251113 CSV & JSON (0) | 2025.11.13 |
|---|---|
| 251113 (0) | 2025.11.13 |
| 251112 Particle (0) | 2025.11.12 |
| 251112 AudioSource (0) | 2025.11.12 |
| 251112 Object Pool (0) | 2025.11.12 |