메모리 풀(Memory Pool) vs 오브젝트 풀(Object Pool)
게임 개발이나 시스템 프로그래밍에서 성능 최적화를 위해 자주 사용하는 두 가지 기법인 메모리 풀(Memory Pool) 과 오브젝트 풀(Object Pool) 은 비슷해 보이지만 목적과 범위가 다릅니다. 아래에서 각각을 비교하고 차이점을 정리합니다.
개념 비교
구분메모리 풀 (Memory Pool)오브젝트 풀 (Object Pool)
목적 | 메모리 할당/해제 비용 절감 | 객체 생성/파괴 비용 절감 |
관리 대상 | 메모리 블록 (raw memory) | 실제 객체 인스턴스 |
주요 사용 시점 | 자주 할당/해제되는 메모리 사용이 필요한 경우 | 자주 생성/삭제되는 객체가 있을 경우 |
구현 방식 | 일정 크기의 메모리 블록을 미리 할당하고 재사용 | 미리 생성한 객체들을 재사용하며, 필요 시 초기화 |
예시 | 게임에서 총알 수천 개의 위치 데이터를 위한 메모리 | 게임에서 총알 객체 자체를 풀로 관리 |
사용 예
- Memory Pool
예: malloc/new 호출을 피하기 위해 64바이트 고정 크기 블록을 미리 수천 개 할당해두고 필요한 시점에 재사용
→ 주로 커스텀 allocator를 만들 때 사용 - Object Pool
예: Bullet 객체 100개를 미리 만들어 두고, 사용이 끝나면 다시 비활성화 후 재사용
→ Unity의 ObjectPool<T>, Unreal의 ChaosCore에서 TObjectPool 사용
메모리 풀 (Memory Pool) 코드 예시
고정 크기 메모리 블록을 미리 여러 개 할당하고, 필요할 때 할당/해제를 반복하는 방식입니다.
#include <iostream>
#include <vector>
#include <cassert>
class MemoryPool
{
private:
struct Block
{
Block* next;
};
char* pool;
Block* freeList;
size_t blockSize;
size_t blockCount;
public:
MemoryPool(size_t blockSize, size_t blockCount)
: blockSize(blockSize), blockCount(blockCount)
{
pool = new char[blockSize * blockCount];
freeList = nullptr;
for (size_t i = 0; i < blockCount; ++i)
{
Block* block = reinterpret_cast<Block*>(pool + i * blockSize);
block->next = freeList;
freeList = block;
}
}
void* allocate()
{
if (!freeList) return nullptr;
Block* block = freeList;
freeList = freeList->next;
return block;
}
void deallocate(void* ptr)
{
Block* block = static_cast<Block*>(ptr);
block->next = freeList;
freeList = block;
}
~MemoryPool()
{
delete[] pool;
}
};
// 사용 예시
struct Vec3
{
float x, y, z;
};
int main()
{
MemoryPool pool(sizeof(Vec3), 100);
void* mem1 = pool.allocate();
void* mem2 = pool.allocate();
Vec3* v1 = new (mem1) Vec3{1, 2, 3}; // placement new
Vec3* v2 = new (mem2) Vec3{4, 5, 6};
std::cout << v1->x << ", " << v2->z << "\n";
v1->~Vec3();
v2->~Vec3();
pool.deallocate(mem1);
pool.deallocate(mem2);
}
Unreal Engine – 오브젝트 풀링 코드 예
ObjectPoolComponent.cpp
#include "ObjectPoolComponent.h"
#include "GameFramework/Actor.h"
UObjectPoolComponent::UObjectPoolComponent()
{
PrimaryComponentTick.bCanEverTick = false;
}
void UObjectPoolComponent::BeginPlay()
{
Super::BeginPlay();
if (!PooledObjectClass) return;
for (int32 i = 0; i < PoolSize; ++i)
{
AActor* NewObj = GetWorld()->SpawnActor<AActor>(PooledObjectClass, FVector::ZeroVector, FRotator::ZeroRotator);
if (NewObj)
{
NewObj->SetActorEnableCollision(false);
NewObj->SetActorHiddenInGame(true);
NewObj->SetActorTickEnabled(false);
Pool.Add(NewObj);
}
}
}
AActor* UObjectPoolComponent::AcquirePooledObject()
{
for (AActor* Obj : Pool)
{
if (Obj && Obj->IsHidden())
{
Obj->SetActorHiddenInGame(false);
Obj->SetActorTickEnabled(true);
Obj->SetActorEnableCollision(true);
return Obj;
}
}
return nullptr; // 풀 다 썼음
}
void UObjectPoolComponent::ReleasePooledObject(AActor* PooledActor)
{
if (PooledActor)
{
PooledActor->SetActorHiddenInGame(true);
PooledActor->SetActorEnableCollision(false);
PooledActor->SetActoTickEnabled(false);
}
}
사용 예시
AActor* Bullet = PoolComponent->AcquirePooledObject();
if (Bullet)
{
Bullet->SetActorLocation(FireLocation);
Bullet->SetActorRotation(FireRotation);
// Bullet->Fire(); 등 로직 실행
// 나중에 Bullet 사용 완료 시:
PoolComponent->ReleasePooledObject(Bullet);
}
'Unreal Engine 5' 카테고리의 다른 글
Unreal Engine 컨테이너 자료구조 정리 (2) | 2025.07.08 |
---|