Asset 참조 관리
Hard vs Soft Reference로 메모리 풋프린트를 최적화합니다
Hard Reference
직접 참조의 문제점
Hard Reference는 오브젝트 A가 오브젝트 B를 직접 참조하여 A가 로드될 때 B도 자동으로 함께 로드됩니다.
연쇄 효과로 불필요한 에셋까지 메모리에 로드됩니다. 주의하지 않으면 게임 시작 시 100% 에셋 로드 상황이 발생할 수 있습니다!
A 로드 → B 자동 로드
연쇄 효과로 메모리 급증
제어 불가
경로 문자열로 참조
로드 시점 직접 제어
메모리 최적화
// Hard Reference - 위험!
UPROPERTY(EditAnywhere)
UStaticMesh* MeshAsset; // 이 클래스 로드 시 메시도 로드
UPROPERTY(EditAnywhere)
TSubclassOf<AActor> ActorClass; // 클래스도 Hard Reference
Hard Reference 발생 원인
| 원인 | 해결책 |
|---|---|
| 직접 UProperty 참조 | TSoftObjectPtr 사용 |
| 블루프린트 캐스팅 | 인터페이스 사용 |
| 직접 클래스 참조 | TSoftClassPtr 사용 |
Soft Reference
간접 참조로 메모리 제어
Soft Reference는 오브젝트 A가 오브젝트 B를 경로 문자열로 간접 참조합니다. 에셋이 자동으로 로드되지 않아 로드 시점을 직접 제어할 수 있습니다.
// Soft Object Pointer
UPROPERTY(EditAnywhere)
TSoftObjectPtr<UStaticMesh> MeshAsset;
// Soft Class Pointer
UPROPERTY(EditAnywhere)
TSoftClassPtr<AActor> ActorClass;
// 로드 확인
if (MeshAsset.IsValid())
{
UStaticMesh* Mesh = MeshAsset.Get();
}
// 동기 로드 (블로킹)
UStaticMesh* Mesh = MeshAsset.LoadSynchronous();
// FStreamableManager를 통한 비동기 로드
FStreamableManager& StreamableManager =
UAssetManager::GetStreamableManager();
StreamableManager.RequestAsyncLoad(
MeshAsset.ToSoftObjectPath(),
FStreamableDelegate::CreateUObject(
this,
&AMyActor::OnMeshLoaded
)
);
void AMyActor::OnMeshLoaded()
{
if (MeshAsset.IsValid())
{
MeshComponent->SetStaticMesh(MeshAsset.Get());
}
}
참조 분석 도구
의존성 확인 및 디버깅
📊 Reference Viewer
그래프로 참조 관계 시각화
Asset > Reference Viewer
📦 Size Map
트리맵으로 에셋 크기 비교
Window > Developer Tools > Size Map
예상보다 큰 에셋이 있다면 Reference Viewer로 숨겨진 의존성을 확인하세요. 종종 불필요한 Hard Reference가 메모리 폭발의 원인입니다.
Asset Manager와 Primary Asset
체계적인 에셋 관리 시스템
UAssetManager는 Primary Asset을 체계적으로 관리하는 싱글톤 시스템입니다. 에셋을 타입별로 분류하고, 비동기 로드/언로드를 중앙에서 제어할 수 있습니다.
// 커스텀 Asset Manager 클래스
UCLASS()
class UMyAssetManager : public UAssetManager
{
GENERATED_BODY()
public:
static UMyAssetManager& Get();
// Primary Asset 비동기 로드
void LoadItemAsset(const FPrimaryAssetId& AssetId,
FStreamableDelegate OnLoaded);
// 번들로 관련 에셋 일괄 로드
void LoadAssetBundle(const FPrimaryAssetId& AssetId,
const TArray<FName>& Bundles);
};
// 사용 예시
FPrimaryAssetId WeaponId(FPrimaryAssetType("Weapon"),
FName("Sword_01"));
UMyAssetManager::Get().LoadItemAsset(WeaponId,
FStreamableDelegate::CreateUObject(
this, &AMyActor::OnWeaponLoaded));
Bundle을 사용하면 상황에 따라 필요한 에셋만 선택적으로 로드할 수 있습니다. 예를 들어 "UI" 번들에는 아이콘만, "Gameplay" 번들에는 메시와 이펙트를 포함시킵니다.
Primary Asset 타입은 반드시 PrimaryAssetTypesToScan에 등록해야 Asset Manager가 인식합니다. 경로와 베이스 클래스를 정확히 지정하세요.
핵심 요약
- Hard Reference: 자동 로드, 연쇄 효과로 메모리 급증 위험
- Soft Reference: 수동 로드, 메모리 제어 가능
- TSoftObjectPtr: 오브젝트 Soft Reference
- TSoftClassPtr: 클래스 Soft Reference
- Asset Manager: Primary Asset 기반 체계적 관리
- Reference Viewer: 의존성 그래프로 참조 관계 분석
다음 강의에서는 Streaming 최적화와 비동기 에셋 로딩 패턴을 다룹니다.
도전 과제
배운 내용을 직접 실습해보세요
프로젝트의 주요 Actor 클래스를 Reference Viewer로 분석하여 불필요한 Hard Reference 체인을 3개 이상 찾고, TSoftObjectPtr/TSoftClassPtr로 변환하세요.
FStreamableManager::RequestAsyncLoad()를 사용하여 무기 메시를 비동기로 로드하는 시스템을 구현하세요. 로드 완료 콜백에서 StaticMesh를 컴포넌트에 할당합니다.
UAssetManager를 상속한 커스텀 Asset Manager를 만들어 Primary Asset 타입(Weapon, Armor)을 등록하고, Bundle 시스템으로 UI용/Gameplay용 에셋을 분리 로드하세요.