대량 객체 생성/파괴
Batch Spawning, Deferred Destruction, GC 트리거 제어로 대량 객체를 효율적으로 관리합니다
Batch Spawning 전략
대량 객체를 프레임 분산하여 생성하는 기법
프레임 분산 스폰
// 한 프레임에 1000개 → 히치!
// for (int i = 0; i < 1000; i++) SpawnActor(...);
// 프레임 분산 스폰
void ASpawnManager::StartBatchSpawn(int32 Total,
int32 PerFrame)
{
PendingSpawnCount = Total;
SpawnPerFrame = PerFrame;
}
void ASpawnManager::Tick(float DeltaTime)
{
if (PendingSpawnCount <= 0) return;
int32 ToSpawn = FMath::Min(SpawnPerFrame, PendingSpawnCount);
for (int32 i = 0; i < ToSpawn; i++)
{
SpawnSingleActor();
PendingSpawnCount--;
}
}
// 결과: 1000개를 20프레임에 걸쳐 50개씩 생성
// 프레임당 GC 부하 = 1/20
Deferred Destruction
대량 파괴를 프레임에 분산하는 지연 파괴 패턴
지연 파괴 큐
UCLASS()
class ADestroyManager : public AActor
{
GENERATED_BODY()
UPROPERTY()
TArray<AActor*> DestroyQueue;
int32 DestroyPerFrame = 10;
public:
void QueueDestroy(AActor* Actor)
{
// 즉시 파괴하지 않고 큐에 추가
Actor->SetActorHiddenInGame(true);
Actor->SetActorEnableCollision(false);
DestroyQueue.Add(Actor);
}
virtual void Tick(float DeltaTime) override
{
int32 Count = FMath::Min(DestroyPerFrame,
DestroyQueue.Num());
for (int32 i = 0; i < Count; i++)
{
AActor* Actor = DestroyQueue[0];
DestroyQueue.RemoveAt(0);
if (Actor)
{
Actor->Destroy();
}
}
}
};
대량 파괴 후 즉시 GC가 실행되면 히치가 발생합니다. DelayGarbageCollection()으로 파괴를 모두 완료한 후 안전한 시점(로딩 스크린 등)에 GC를 실행하세요.
GC 트리거 제어
프로그래밍적 GC 실행 타이밍 제어
전략적 GC 호출
// 레벨 전환 시 GC 패턴
void AMyGameMode::TransitionToLevel(FName NewLevel)
{
// 1. GC 지연 시작
GEngine->DelayGarbageCollection();
// 2. 현재 레벨 정리
CleanupCurrentLevel();
// 3. 로딩 스크린 표시
ShowLoadingScreen();
// 4. 강제 Full GC (로딩 스크린 중 - 히치 무관)
CollectGarbage(GARBAGE_COLLECTION_KEEPFLAGS, true);
// 5. 새 레벨 로드
UGameplayStatics::OpenLevel(this, NewLevel);
}
// 웨이브 사이 GC 패턴 (PvE 게임)
void AWaveManager::OnWaveCompleted()
{
// 웨이브 간 전환 연출 중 GC
CollectGarbage(GARBAGE_COLLECTION_KEEPFLAGS);
PrepareNextWave();
}
Mass Entity 대안
UObject가 아닌 경량 엔티티로 대량 객체 관리
GC를 피하는 설계
수천~수만 개의 유사 객체(군중, 탄막 등)는 UObject/AActor로 만들면 GC 부하가 심합니다. GC를 완전히 피하는 대안을 고려하세요.
// 대안 1: 구조체 배열 (GC 대상 아님)
USTRUCT()
struct FProjectileData
{
GENERATED_BODY()
FVector Location;
FVector Velocity;
float Damage;
float Lifetime;
};
UPROPERTY()
TArray<FProjectileData> Projectiles; // 10000개도 GC 부하 0
// 대안 2: Mass Entity Framework (UE 5.0+)
// ECS 기반의 경량 엔티티 시스템
// 수만 개의 엔티티를 GC 없이 관리
// 대안 3: Instanced Static Mesh
// 시각적으로만 필요한 대량 객체
UInstancedStaticMeshComponent* ISMC;
ISMC->AddInstance(FTransform(Location));
// 1개의 컴포넌트로 수천 개 렌더링
10,000개 객체 기준: UObject 사용 시 GC Mark만 ~5ms, 구조체 배열은 GC 비용 0ms. 대량 동일 객체는 반드시 GC를 피하는 설계를 먼저 고려하세요.
핵심 요약
- Batch Spawning으로 대량 생성을 여러 프레임에 분산합니다
- Deferred Destruction으로 대량 파괴를 프레임당 제한된 수만 처리합니다
- 레벨 전환 등 안전한 시점에 전략적으로 GC를 호출합니다
- 수천 개 이상의 유사 객체는 구조체 배열이나 Mass Entity를 사용하여 GC를 피합니다
- Instanced Static Mesh로 시각적 대량 객체를 효율적으로 처리합니다
도전 과제
배운 내용을 직접 실습해보세요
1,000 / 10,000 / 100,000개의 UObject를 생성하고 삭제하면서 GC 소요 시간, 메모리 사용량, 프레임 히치를 측정하세요. 각 규모에서의 병목 지점(Mark vs Sweep vs Destroy)을 식별하세요.
대량의 데이터 객체가 필요한 경우, UObject 대신 FStructOnScope 또는 일반 USTRUCT를 사용하여 GC 추적 오버헤드를 회피하는 패턴을 구현하세요. UObject 버전과 메모리/성능을 비교하세요.
UWorldSubsystem을 기반으로 대량의 게임플레이 객체(아이템, NPC 상태 등)를 효율적으로 관리하는 시스템을 설계하세요. USTRUCT 데이터 + Handle 패턴으로 GC 부하를 최소화하면서 UObject의 편의성을 유지하는 아키텍처를 구현하세요.