PART 4 · 강의 2/4

메모리 누수 탐지

Reference Viewer, Size Map, 참조 체인 추적으로 GC가 수집하지 못하는 객체를 찾습니다

SECTION 01

Reference Viewer

에디터에서 에셋 참조 그래프를 시각적으로 분석

Reference Viewer 사용법

에디터의 Reference Viewer는 에셋 간 참조 관계를 그래프로 보여줍니다. 에셋을 우클릭 → "Reference Viewer"로 열 수 있습니다.

사용 순서 // 1. 콘텐츠 브라우저에서 의심 에셋 우클릭 // 2. "Reference Viewer" 선택 // 3. 참조 그래프 분석: 왼쪽 노드 → 이 에셋을 참조하는 에셋 (Referencers) 중앙 노드 → 선택한 에셋 오른쪽 노드 → 이 에셋이 참조하는 에셋 (Dependencies) // 핵심 확인 사항: // - 예상치 못한 참조자(Referencer)가 있는지 // - 순환 참조 경로가 있는지 // - 불필요한 에셋이 참조 체인에 있는지 // 옵션: // Show Referencers: 참조자 표시 깊이 설정 // Show Dependencies: 의존성 표시 깊이 설정 // Show Soft References: 소프트 참조 포함 여부
누수 탐지 팁

레벨 전환 후에도 메모리가 줄지 않으면, 이전 레벨의 에셋이 Reference Viewer에서 여전히 참조자를 가지고 있을 수 있습니다. "Show Referencers" 깊이를 높여 전체 참조 체인을 추적하세요.

SECTION 02

Size Map과 메모리 프로파일링

에셋별 메모리 사용량을 시각적으로 분석

Size Map 도구

Size Map은 에셋이 차지하는 메모리(디스크 및 메모리)를 트리맵으로 시각화합니다. 에셋을 우클릭 → "Size Map"으로 열 수 있습니다.

분석 방법 // Size Map에서 확인할 항목: 1. Memory Size: 메모리에 로드된 크기 2. Disk Size: 디스크 저장 크기 3. Dependencies: 의존 에셋 포함 크기 // 큰 블록 = 메모리 다량 사용 // 예상치 못한 큰 블록 = 불필요한 에셋 로드 가능성 // 프로그래밍적 메모리 추적 FResourceSizeEx ResourceSize; MyObject->GetResourceSizeEx(ResourceSize); UE_LOG(LogTemp, Log, TEXT("Exclusive: %lld, Inclusive: %lld"), ResourceSize.GetDedicatedSystemMemoryBytes(), ResourceSize.GetTotalMemoryBytes());
SECTION 03

프로그래밍적 누수 탐지

코드를 통한 메모리 누수 자동 감지 방법

런타임 누수 감지 패턴

C++ // 패턴 1: 클래스별 인스턴스 카운터 UCLASS() class UMyObject : public UObject { GENERATED_BODY() public: static int32 InstanceCount; UMyObject() { ++InstanceCount; } virtual void BeginDestroy() override { --InstanceCount; Super::BeginDestroy(); } }; // 주기적으로 InstanceCount 모니터링 // 패턴 2: obj list를 프로그래밍적으로 int32 Count = 0; for (TObjectIterator<UMyObject> It; It; ++It) { Count++; } UE_LOG(LogGC, Warning, TEXT("UMyObject count: %d"), Count); // 패턴 3: GC 후 비교 int32 BeforeGC = CountObjects(); CollectGarbage(GARBAGE_COLLECTION_KEEPFLAGS); int32 AfterGC = CountObjects(); if (BeforeGC - AfterGC < ExpectedDecrease) { UE_LOG(LogGC, Error, TEXT("Potential leak: only %d collected"), BeforeGC - AfterGC); }
TObjectIterator 사용 주의

TObjectIterator는 GUObjectArray를 전체 순회하므로 성능 비용이 높습니다. 프로덕션 코드에서는 사용을 피하고, 디버그/테스트 빌드에서만 사용하세요. 대안으로 Automation Test에서 메모리 누수 체크를 수행하는 것이 좋습니다.

SECTION 04

Low-Level Memory Tracker (LLM)

엔진 수준의 메모리 추적 시스템 활용

LLM 사용법

커맨드라인/콘솔 // 커맨드 라인으로 LLM 활성화 -LLM -LLMCSV // CSV 파일로 출력 -LLMTagSets // 태그셋별 추적 // 콘솔에서 stat LLM // LLM 통계 표시 stat LLMFULL // 상세 LLM 통계 // 출력 항목: Total 512.3 MB UObject 89.2 MB ← GC 관리 메모리 Textures 156.4 MB StaticMesh 45.1 MB Animation 23.8 MB Audio 12.5 MB Physics 18.9 MB
LLM과 GC의 관계

LLM의 "UObject" 카테고리가 GC 관리 대상 메모리입니다. 이 값이 계속 증가하면 GC가 수집하지 못하는 객체가 있다는 의미입니다. 시간 경과에 따른 추이를 CSV로 기록하여 누수를 발견하세요.

SUMMARY

핵심 요약

이 강의에서 배운 내용
  • Reference Viewer로 에셋 간 참조 그래프를 시각적으로 분석하여 누수 원인을 추적합니다
  • Size Map으로 에셋별 메모리 사용량을 확인하고 불필요한 로드를 발견합니다
  • TObjectIterator와 인스턴스 카운터로 프로그래밍적 누수 감지가 가능합니다
  • LLM의 UObject 카테고리 추이를 관찰하여 장기 메모리 누수를 발견합니다
  • GC 후에도 obj list 결과가 줄지 않으면 참조 누수를 의심합니다
PRACTICE

도전 과제

배운 내용을 직접 실습해보세요

실습 1: 의도적 메모리 누수 생성 및 탐지

AddToRoot()로 Root Set에 등록 후 RemoveFromRoot()를 호출하지 않는 UObject, UPROPERTY에 참조를 유지한 채 해제하지 않는 패턴 등 3가지 의도적 누수 시나리오를 만들고, memreport -full로 탐지하세요.

실습 2: 참조 체인 추적으로 누수 원인 분석

obj refs name=MyLeakingObject 명령어로 특정 객체에 대한 참조 체인을 추적하세요. 어떤 경로로 Root Set까지 연결되어 GC가 수집하지 못하는지 참조 경로를 시각화하세요.

심화 과제: 자동 메모리 누수 감지 테스트 구현

Automation Test 프레임워크를 사용하여 특정 기능 실행 전후의 UObject 수를 비교하는 메모리 누수 테스트를 작성하세요. 레벨 로드/언로드 사이클에서 객체가 정상적으로 정리되는지 자동으로 검증하세요.