PART 4 ยท ๊ฐ•์˜ 4/4

๋คํ”„ ๋ถ„์„

obj dump, FMalloc ํžˆ์Šคํ† ๋ฆฌ, ์ปค์Šคํ…€ ๋ฉ”๋ชจ๋ฆฌ ๋ฆฌํฌํŠธ๋กœ GC ๋ฌธ์ œ๋ฅผ ๊นŠ์ด ์ง„๋‹จํ•ฉ๋‹ˆ๋‹ค

SECTION 01

obj dump ๋ช…๋ น์–ด

ํŠน์ • UObject์˜ ์ƒ์„ธ ํ”„๋กœํผํ‹ฐ๋ฅผ ๋คํ”„ํ•˜์—ฌ ๋ถ„์„

obj dump ์‚ฌ์šฉ๋ฒ•

์ฝ˜์†” // ํŠน์ • ๊ฐ์ฒด์˜ ํ”„๋กœํผํ‹ฐ ๋คํ”„ obj dump MyActor_42 // ์ถœ๋ ฅ ์˜ˆ์‹œ: Object: MyActor_42 (Class: AMyActor) Outer: PersistentLevel Flags: RF_Transactional InternalFlags: None Properties: Health = 100 MeshComponent = StaticMeshComponent_0 TargetActor = OtherActor_15 โ† ์ฐธ์กฐ ํ™•์ธ! Inventory = [UItem_0, UItem_1, UItem_2] // ํด๋ž˜์Šค ๋‹จ์œ„ ๋คํ”„ obj dump class=AMyActor // Outer ์ฒด์ธ ํ™•์ธ (์†Œ์œ ๊ถŒ ๊ตฌ์กฐ) // MyActor_42 โ†’ PersistentLevel โ†’ World โ†’ Package
๋คํ”„์—์„œ GC ๋ฌธ์ œ ๋ฐœ๊ฒฌํ•˜๊ธฐ

obj dump์—์„œ ํ™•์ธํ•  ํ•ต์‹ฌ ์‚ฌํ•ญ:

  • Outer ์ฒด์ธ: ์˜ˆ์ƒ์น˜ ๋ชปํ•œ Outer๊ฐ€ ์žˆ์œผ๋ฉด GC ์ˆ˜๋ช…์ด ๋‹ฌ๋ผ์งˆ ์ˆ˜ ์žˆ์Œ
  • Flags: RF_Standalone์ด ๋ถˆํ•„์š”ํ•˜๊ฒŒ ์„ค์ •๋˜์–ด ์žˆ์ง€ ์•Š์€์ง€
  • ์ฐธ์กฐ ํ”„๋กœํผํ‹ฐ: ํŒŒ๊ดด๋˜์–ด์•ผ ํ•  ๊ฐ์ฒด๋ฅผ ์—ฌ์ „ํžˆ ์ฐธ์กฐํ•˜๋Š”์ง€
SECTION 02

๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น ์ถ”์  (FMalloc)

์—”์ง„์˜ ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น๊ธฐ๋ฅผ ํ™œ์šฉํ•œ ์ €์ˆ˜์ค€ ์ถ”์ 

FMalloc ๊ธฐ๋ฐ˜ ์ถ”์ 

์ปค๋งจ๋“œ๋ผ์ธ // ๋ฉ”๋ชจ๋ฆฌ ํžˆ์Šคํ† ๋ฆฌ ์ถ”์  ํ™œ์„ฑํ™” -MallocFrameProfiler // ํ”„๋ ˆ์ž„๋ณ„ ํ• ๋‹น ํ”„๋กœํŒŒ์ผ๋ง -MallocLeakReporting // ๋ˆ„์ˆ˜ ๋ฆฌํฌํŠธ // ๋Ÿฐํƒ€์ž„ ๋ฉ”๋ชจ๋ฆฌ ํ†ต๊ณ„ stat memory // ์ถœ๋ ฅ: Total Physical: 16384 MB Used Physical: 8234 MB Peak Physical: 9120 MB Used Virtual: 12450 MB // ๋ฉ”๋ชจ๋ฆฌ ๋ฆฌํฌํŠธ ์ถœ๋ ฅ memreport -full // ๊ฒฐ๊ณผ ํŒŒ์ผ: Saved/Profiling/MemReports/ // MemReport_YYYY-MM-DD_HH-MM-SS.memreport

memreport ํŒŒ์ผ ๋ถ„์„

memreport ๋‚ด์šฉ // memreport ํŒŒ์ผ์˜ ์ฃผ์š” ์„น์…˜: === UObject Count === Total UObjects: 85,234 AStaticMeshActor: 12,500 UStaticMeshComponent: 12,500 UMaterial: 3,200 UTexture2D: 2,800 ... === Memory by Category === UObject Overhead: 45.2 MB FName Table: 12.8 MB TArray Slack: 8.4 MB Texture Memory: 156.4 MB === Top Memory Consumers === T_LargeTexture_4K: 64.0 MB SM_ComplexMesh: 32.5 MB SK_Character: 16.2 MB
SECTION 03

์ปค์Šคํ…€ ๋ฉ”๋ชจ๋ฆฌ ๋ฆฌํฌํŠธ

ํ”„๋กœ์ ํŠธ ํŠนํ™” ๋ฉ”๋ชจ๋ฆฌ ์ง„๋‹จ ๋„๊ตฌ ๊ตฌ์ถ•

์ปค์Šคํ…€ ๋ฆฌํฌํŠธ ๊ตฌํ˜„

C++ // ์ปค์Šคํ…€ GC ๋ฆฌํฌํŠธ Exec ๋ช…๋ น static bool Exec_GCReport(UWorld* World, const TCHAR* Cmd) { TMap<UClass*, int32> ClassCounts; TMap<UClass*, SIZE_T> ClassMemory; for (FThreadSafeObjectIterator It; It; ++It) { UObject* Obj = *It; ClassCounts.FindOrAdd(Obj->GetClass())++; FResourceSizeEx Size; Obj->GetResourceSizeEx(Size); ClassMemory.FindOrAdd(Obj->GetClass()) += Size.GetTotalMemoryBytes(); } // ๊ฒฐ๊ณผ ์ •๋ ฌ ๋ฐ ์ถœ๋ ฅ ClassCounts.ValueSort([](int32 A, int32 B) { return A > B; }); UE_LOG(LogGC, Warning, TEXT("=== GC Report ===")); for (auto& Pair : ClassCounts) { UE_LOG(LogGC, Warning, TEXT(" %s: %d objects, %.2f MB"), *Pair.Key->GetName(), Pair.Value, ClassMemory[Pair.Key] / 1024.0 / 1024.0); } return true; }
SECTION 04

ํฌ๋ž˜์‹œ ๋คํ”„์—์„œ GC ๋ถ„์„

ํฌ๋ž˜์‹œ ๋คํ”„ ํŒŒ์ผ์—์„œ GC ๊ด€๋ จ ๋ฌธ์ œ๋ฅผ ์ง„๋‹จํ•˜๋Š” ๋ฐฉ๋ฒ•

GC ๊ด€๋ จ ํฌ๋ž˜์‹œ ํŒจํ„ด

ํฌ๋ž˜์‹œ ํŒจํ„ด // ํŒจํ„ด 1: ๋Œ•๊ธ€๋ง ํฌ์ธํ„ฐ ์ ‘๊ทผ Access Violation at 0xDDDDDDDD // โ†’ UPROPERTY ๋ˆ„๋ฝ์œผ๋กœ GC๋œ ๊ฐ์ฒด ์ ‘๊ทผ // ํŒจํ„ด 2: GC ์ค‘ ์ ‘๊ทผ Assertion failed: !IsGarbageCollecting() // โ†’ GC ์ง„ํ–‰ ์ค‘ UObject ์ƒ์„ฑ/ํŒŒ๊ดด ์‹œ๋„ // ํŒจํ„ด 3: ์œ ํšจํ•˜์ง€ ์•Š์€ UObject Fatal: UObject has invalid Flags // โ†’ ์ด๋ฏธ ํŒŒ๊ดด๋œ UObject์˜ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋‹ค๋ฅธ ์šฉ๋„๋กœ ์žฌ์‚ฌ์šฉ // ํŒจํ„ด 4: FinishDestroy ์ค‘ ํฌ๋ž˜์‹œ Crash in UMyObject::FinishDestroy // โ†’ BeginDestroy์—์„œ ๋ฆฌ์†Œ์Šค ์ •๋ฆฌ ๋ฏธํก // ๋””๋ฒ„๊ฑฐ์—์„œ ํ™•์ธํ•  ๊ฒƒ: // 1. GUObjectArray์—์„œ ํ•ด๋‹น ์ธ๋ฑ์Šค ํ™•์ธ // 2. FUObjectItem์˜ Flags ํ™•์ธ // 3. SerialNumber ์ผ์น˜ ์—ฌ๋ถ€ ํ™•์ธ
0xDDDDDDDD ํŒจํ„ด

Visual Studio ๋””๋ฒ„๊ทธ ๋นŒ๋“œ์—์„œ ํ•ด์ œ๋œ ๋ฉ”๋ชจ๋ฆฌ๋Š” 0xDD๋กœ ์ฑ„์›Œ์ง‘๋‹ˆ๋‹ค. ์ ‘๊ทผ ์œ„๋ฐ˜ ์ฃผ์†Œ๊ฐ€ 0xDDDDDDDD ๊ทผ์ฒ˜์ด๋ฉด ์ด๋ฏธ GC๋œ UObject์— ์ ‘๊ทผํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. UPROPERTY() ๋ˆ„๋ฝ์ด ๊ฐ€์žฅ ํ”ํ•œ ์›์ธ์ž…๋‹ˆ๋‹ค.

SUMMARY

ํ•ต์‹ฌ ์š”์•ฝ

์ด ๊ฐ•์˜์—์„œ ๋ฐฐ์šด ๋‚ด์šฉ
  • obj dump์œผ๋กœ ํŠน์ • UObject์˜ ํ”„๋กœํผํ‹ฐ, Outer ์ฒด์ธ, ํ”Œ๋ž˜๊ทธ๋ฅผ ์ƒ์„ธํžˆ ๋ถ„์„ํ•ฉ๋‹ˆ๋‹ค
  • memreport -full๋กœ ์ „์ฒด ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰ ๋ฆฌํฌํŠธ๋ฅผ ํŒŒ์ผ๋กœ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค
  • ์ปค์Šคํ…€ GC ๋ฆฌํฌํŠธ๋ฅผ ๊ตฌํ˜„ํ•˜์—ฌ ํ”„๋กœ์ ํŠธ ํŠนํ™” ๋ฉ”๋ชจ๋ฆฌ ์ง„๋‹จ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค
  • 0xDDDDDDDD ํฌ๋ž˜์‹œ๋Š” GC๋œ UObject ์ ‘๊ทผ(UPROPERTY ๋ˆ„๋ฝ)์ด ์›์ธ์ž…๋‹ˆ๋‹ค
  • stat memory์™€ LLM์„ ๋ณ‘ํ–‰ํ•˜์—ฌ ์ „์ฒด ๋ฉ”๋ชจ๋ฆฌ ์ƒํƒœ๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋งํ•ฉ๋‹ˆ๋‹ค
PRACTICE

๋„์ „ ๊ณผ์ œ

๋ฐฐ์šด ๋‚ด์šฉ์„ ์ง์ ‘ ์‹ค์Šตํ•ด๋ณด์„ธ์š”

์‹ค์Šต 1: memreport ๋ถ„์„ ์‹ค์Šต

memreport -full ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜์—ฌ ์ƒ์„ฑ๋œ .memreport ํŒŒ์ผ์„ ๋ถ„์„ํ•˜์„ธ์š”. UObject ํด๋ž˜์Šค๋ณ„ ์ธ์Šคํ„ด์Šค ์ˆ˜, ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰, ๊ฐ€์žฅ ํฐ ๊ฐ์ฒด ๋ชฉ๋ก์„ ์ •๋ฆฌํ•˜๊ณ , ๋น„์ •์ƒ์ ์œผ๋กœ ๋งŽ์€ ์ธ์Šคํ„ด์Šค๋ฅผ ๊ฐ€์ง„ ํด๋ž˜์Šค๋ฅผ ์‹๋ณ„ํ•˜์„ธ์š”.

์‹ค์Šต 2: Obj Dump๋ฅผ ์ด์šฉํ•œ ๊ฐœ๋ณ„ ๊ฐ์ฒด ๋ถ„์„

obj dump ๋ช…๋ น์–ด๋กœ ํŠน์ • UObject์˜ ์ „์ฒด ํ”„๋กœํผํ‹ฐ ๋คํ”„๋ฅผ ํ™•์ธํ•˜์„ธ์š”. UPROPERTY ๊ฐ’, ์ฐธ์กฐํ•˜๋Š” ์™ธ๋ถ€ ๊ฐ์ฒด, Object Flags ๋“ฑ์„ ๋ถ„์„ํ•˜์—ฌ ํ•ด๋‹น ๊ฐ์ฒด์˜ GC ๊ด€๋ จ ์ƒํƒœ๋ฅผ ์ข…ํ•ฉ์ ์œผ๋กœ ํŒŒ์•…ํ•˜์„ธ์š”.

์‹ฌํ™” ๊ณผ์ œ: ๋ฉ”๋ชจ๋ฆฌ ์Šค๋ƒ…์ƒท ๋น„๊ต ๋„๊ตฌ ๊ตฌํ˜„

๋‘ ์‹œ์ ์˜ memreport๋ฅผ ์ž๋™์œผ๋กœ ๋น„๊ตํ•˜์—ฌ ์ƒˆ๋กœ ์ƒ์„ฑ๋œ ๊ฐ์ฒด, ์‚ญ์ œ๋œ ๊ฐ์ฒด, ๋ฉ”๋ชจ๋ฆฌ ์ฆ๊ฐ€/๊ฐ์†Œ๋ฅผ ๋ณด๊ณ ํ•˜๋Š” Python ๋˜๋Š” C++ ๋„๊ตฌ๋ฅผ ๊ฐœ๋ฐœํ•˜์„ธ์š”. ๋ ˆ๋ฒจ ์ „ํ™˜ ์ „ํ›„์˜ ๋ฉ”๋ชจ๋ฆฌ ๋ณ€ํ™”๋ฅผ ์ž๋™ ๋ถ„์„ํ•˜์„ธ์š”.