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

Level Streaming๊ณผ GC

๋ ˆ๋ฒจ ์–ธ๋กœ๋“œ ์‹œ GC ๋™์ž‘, FlushStreamingLevel, ์ง€์—ฐ GC ์ „๋žต์„ ๋ถ„์„ํ•ฉ๋‹ˆ๋‹ค

SECTION 01

๋ ˆ๋ฒจ ์–ธ๋กœ๋“œ์™€ GC

์„œ๋ธŒ๋ ˆ๋ฒจ์ด ์–ธ๋กœ๋“œ๋  ๋•Œ GC๊ฐ€ ๋™์ž‘ํ•˜๋Š” ๊ณผ์ •

๋ ˆ๋ฒจ ์–ธ๋กœ๋“œ ์‹œ GC ํ๋ฆ„

ํ๋ฆ„ UnloadStreamingLevel(SubLevel) โ”‚ โ”œโ”€โ”€ SubLevel์˜ ๋ชจ๋“  Actor์— Destroy() ํ˜ธ์ถœ โ”‚ โ””โ”€โ”€ ๊ฐ Actor: MarkAsGarbage() โ”‚ โ”œโ”€โ”€ SubLevel์˜ ULevelStreaming ์ƒํƒœ ๋ณ€๊ฒฝ โ”‚ โ””โ”€โ”€ Unloaded ์ƒํƒœ๋กœ ์ „ํ™˜ โ”‚ โ”œโ”€โ”€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ฆ‰์‹œ GC ์‹คํ–‰ โ”‚ โ””โ”€โ”€ CollectGarbage(GARBAGE_COLLECTION_KEEPFLAGS) โ”‚ โ””โ”€โ”€ ๊ฒฐ๊ณผ: โ”œโ”€โ”€ ์–ธ๋กœ๋“œ๋œ ๋ ˆ๋ฒจ์˜ Actor๋“ค ๋ฉ”๋ชจ๋ฆฌ ํ•ด์ œ โ”œโ”€โ”€ ํ•ด๋‹น ๋ ˆ๋ฒจ ์ „์šฉ ์—์…‹๋“ค๋„ ์ฐธ์กฐ ์—†์œผ๋ฉด GC โ””โ”€โ”€ ์ด ๊ณผ์ •์—์„œ GC ํžˆ์น˜ ๋ฐœ์ƒ ๊ฐ€๋Šฅ!
๋ ˆ๋ฒจ ์–ธ๋กœ๋“œ GC ํžˆ์น˜

์„œ๋ธŒ๋ ˆ๋ฒจ ์–ธ๋กœ๋“œ ์งํ›„์˜ GC๋Š” Full GC๋กœ ์‹คํ–‰๋  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ˆ˜์ฒœ ๊ฐœ์˜ Actor์™€ ์—์…‹์„ ํ•œ ๋ฒˆ์— ์ฒ˜๋ฆฌํ•˜๋ฏ€๋กœ ์‹ฌ๊ฐํ•œ ํžˆ์น˜๋ฅผ ์œ ๋ฐœํ•ฉ๋‹ˆ๋‹ค. ํŠนํžˆ ์˜คํ”ˆ์›”๋“œ์—์„œ ๋นˆ๋ฒˆํ•œ ๋ ˆ๋ฒจ ์ŠคํŠธ๋ฆฌ๋ฐ ์‹œ ์ด ๋ฌธ์ œ๊ฐ€ ๋‘๋“œ๋Ÿฌ์ง‘๋‹ˆ๋‹ค.

SECTION 02

GC ํƒ€์ด๋ฐ ์ œ์–ด ์ „๋žต

๋ ˆ๋ฒจ ์ŠคํŠธ๋ฆฌ๋ฐ๊ณผ GC ์‹คํ–‰์„ ๋ถ„๋ฆฌํ•˜๋Š” ๊ธฐ๋ฒ•

์ง€์—ฐ GC ์ „๋žต

C++ // ์ „๋žต 1: ๋ ˆ๋ฒจ ์–ธ๋กœ๋“œ ์‹œ GC ์ง€์—ฐ // ์–ธ๋กœ๋“œ ์ „์— GC๋ฅผ ์ง€์—ฐ์‹œํ‚ค๊ณ , ์•ˆ์ „ํ•œ ์‹œ์ ์— ์ˆ˜๋™ ์‹คํ–‰ GEngine->DelayGarbageCollection(); UnloadStreamLevel(SubLevelName); // ... ๋กœ๋”ฉ ์Šคํฌ๋ฆฐ์ด๋‚˜ ์•ˆ์ „ํ•œ ์‹œ์ ์—์„œ ... CollectGarbage(GARBAGE_COLLECTION_KEEPFLAGS); // ์ „๋žต 2: Incrementalํ•˜๊ฒŒ ์ฒ˜๋ฆฌ // gc.TimeLimitSeconds๋ฅผ ์„ค์ •ํ•˜๋ฉด ๋ ˆ๋ฒจ ์–ธ๋กœ๋“œ ํ›„ // GC๊ฐ€ ์—ฌ๋Ÿฌ ํ”„๋ ˆ์ž„์— ๋ถ„์‚ฐ๋จ // ์ „๋žต 3: ๋กœ๋”ฉ ์Šคํฌ๋ฆฐ ์ค‘ GC void UMyGameInstance::OnLevelTransition() { // ๋กœ๋”ฉ ์Šคํฌ๋ฆฐ ํ‘œ์‹œ ShowLoadingScreen(); // ์ด์ „ ๋ ˆ๋ฒจ ์–ธ๋กœ๋“œ UnloadCurrentLevel(); // ๋กœ๋”ฉ ์Šคํฌ๋ฆฐ ์ค‘ Full GC (ํžˆ์น˜ ๋ฌด๊ด€) CollectGarbage(GARBAGE_COLLECTION_KEEPFLAGS, true); // ์ƒˆ ๋ ˆ๋ฒจ ๋กœ๋“œ LoadNewLevel(); HideLoadingScreen(); }
SECTION 03

World Partition๊ณผ GC

UE5 World Partition ์‹œ์Šคํ…œ์—์„œ์˜ GC ๊ณ ๋ ค์‚ฌํ•ญ

World Partition์˜ GC ํŠน์„ฑ

UE5์˜ World Partition์€ ๋ ˆ๋ฒจ์„ ์…€(Cell) ๋‹จ์œ„๋กœ ์ž๋™ ๋ถ„ํ• ํ•˜๊ณ  ์ŠคํŠธ๋ฆฌ๋ฐํ•ฉ๋‹ˆ๋‹ค. ์ „ํ†ต์ ์ธ ์„œ๋ธŒ๋ ˆ๋ฒจ๋ณด๋‹ค ๋” ์„ธ๋ถ„ํ™”๋œ ์ŠคํŠธ๋ฆฌ๋ฐ์ด ๊ฐ€๋Šฅํ•˜๋ฉฐ, GC ๋™์ž‘๋„ ๋‹ฌ๋ผ์ง‘๋‹ˆ๋‹ค.

World Partition GC ํŠน์„ฑ // World Partition ์…€ ์–ธ๋กœ๋“œ ์‹œ 1. ์…€ ๋‚ด Actor๋“ค์ด ๋น„ํ™œ์„ฑํ™”/ํŒŒ๊ดด 2. ์ž‘์€ ๋‹จ์œ„(์…€)๋กœ ์–ธ๋กœ๋“œ๋˜๋ฏ€๋กœ GC ๋ถ€ํ•˜ ๋ถ„์‚ฐ 3. Data Layer๋ณ„ ๋…๋ฆฝ์  ์ŠคํŠธ๋ฆฌ๋ฐ ๊ฐ€๋Šฅ // ๊ด€๋ จ ์„ค์ • [/Script/Engine.WorldPartition] RuntimeHashClass=RuntimeSpatialHash bEnableStreaming=True LoadingRange=25600 // ๋กœ๋”ฉ ๋ฒ”์œ„ (cm) // GC ์ตœ์ ํ™” ํฌ์ธํŠธ: // - ์…€ ํฌ๊ธฐ๋ฅผ ์ ์ ˆํžˆ ์„ค์ • (๋„ˆ๋ฌด ์ž‘์œผ๋ฉด ๋นˆ๋ฒˆํ•œ ์ŠคํŠธ๋ฆฌ๋ฐ) // - HLOD๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์›๊ฑฐ๋ฆฌ ๊ฐ์ฒด ์ˆ˜ ๊ฐ์†Œ // - One File Per Actor๋กœ ์„ธ๋ถ„ํ™”๋œ ๋กœ๋”ฉ
World Partition์—์„œ์˜ GC ํŒ

World Partition์€ ์…€ ๋‹จ์œ„ ์ŠคํŠธ๋ฆฌ๋ฐ์œผ๋กœ GC ๋ถ€ํ•˜๊ฐ€ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋ถ„์‚ฐ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ํ”Œ๋ ˆ์ด์–ด๊ฐ€ ๋น ๋ฅด๊ฒŒ ์ด๋™ํ•˜๋ฉด ๋งŽ์€ ์…€์ด ๋™์‹œ์— ์–ธ๋กœ๋“œ๋˜์–ด GC ์ŠคํŒŒ์ดํฌ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋™ ์†๋„์— ๋งž์ถฐ LoadingRange๋ฅผ ์กฐ์ •ํ•˜์„ธ์š”.

SECTION 04

์—์…‹ ์ฐธ์กฐ์™€ ๋ ˆ๋ฒจ GC

๋ ˆ๋ฒจ ๊ฐ„ ์—์…‹ ์ฐธ์กฐ๊ฐ€ GC์— ๋ฏธ์น˜๋Š” ์˜ํ–ฅ

ํฌ๋กœ์Šค ๋ ˆ๋ฒจ ์ฐธ์กฐ ๋ฌธ์ œ

๋ฌธ์ œ ์ƒํ™ฉ // ๋ฌธ์ œ: ์„œ๋ธŒ๋ ˆ๋ฒจ B๊ฐ€ ์„œ๋ธŒ๋ ˆ๋ฒจ A์˜ ์—์…‹์„ ์ฐธ์กฐ SubLevel_A: SM_LargeBuilding (100MB) SubLevel_B: Actor๊ฐ€ SM_LargeBuilding์„ ์ฐธ์กฐ // SubLevel_A๋ฅผ ์–ธ๋กœ๋“œํ•ด๋„ // SubLevel_B์˜ ์ฐธ์กฐ๋กœ SM_LargeBuilding์ด GC๋˜์ง€ ์•Š์Œ! // โ†’ 100MB๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ์— ์ž”๋ฅ˜ // ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•: 1. TSoftObjectPtr ์‚ฌ์šฉ โ†’ ์•ฝํ•œ ์ฐธ์กฐ์ด๋ฏ€๋กœ ์—์…‹ GC ๊ฐ€๋Šฅ 2. ๊ณต์œ  ์—์…‹ ๋ ˆ๋ฒจ ๋ถ„๋ฆฌ โ†’ SharedAssets ๋ ˆ๋ฒจ์— ๊ณตํ†ต ์—์…‹ ๋ฐฐ์น˜ 3. ์—์…‹ ๋งค๋‹ˆ์ € ํ™œ์šฉ โ†’ Primary Asset์œผ๋กœ ๋ช…์‹œ์  ๋กœ๋“œ/์–ธ๋กœ๋“œ
SUMMARY

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

์ด ๊ฐ•์˜์—์„œ ๋ฐฐ์šด ๋‚ด์šฉ
  • ๋ ˆ๋ฒจ ์–ธ๋กœ๋“œ ์งํ›„์˜ Full GC๋Š” ์‹ฌ๊ฐํ•œ ํžˆ์น˜๋ฅผ ์œ ๋ฐœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค
  • DelayGarbageCollection()๊ณผ ๋กœ๋”ฉ ์Šคํฌ๋ฆฐ์„ ํ™œ์šฉํ•˜์—ฌ GC ํƒ€์ด๋ฐ์„ ์ œ์–ดํ•ฉ๋‹ˆ๋‹ค
  • World Partition์€ ์…€ ๋‹จ์œ„ ์ŠคํŠธ๋ฆฌ๋ฐ์œผ๋กœ GC ๋ถ€ํ•˜๋ฅผ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋ถ„์‚ฐํ•ฉ๋‹ˆ๋‹ค
  • ํฌ๋กœ์Šค ๋ ˆ๋ฒจ ์—์…‹ ์ฐธ์กฐ๋Š” ์–ธ๋กœ๋“œ ํ›„์—๋„ ๋ฉ”๋ชจ๋ฆฌ ์ž”๋ฅ˜๋ฅผ ์œ ๋ฐœํ•˜๋ฏ€๋กœ TSoftObjectPtr๋ฅผ ํ™œ์šฉํ•ฉ๋‹ˆ๋‹ค
  • ์˜คํ”ˆ์›”๋“œ์—์„œ๋Š” LoadingRange์™€ ์…€ ํฌ๊ธฐ๋ฅผ ์ ์ ˆํžˆ ์กฐ์ •ํ•˜์—ฌ GC ์ŠคํŒŒ์ดํฌ๋ฅผ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค
PRACTICE

๋„์ „ ๊ณผ์ œ

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

์‹ค์Šต 1: ๋ ˆ๋ฒจ ์ŠคํŠธ๋ฆฌ๋ฐ๊ณผ GC ์ƒํ˜ธ์ž‘์šฉ ๊ด€์ฐฐ

World Partition ๋˜๋Š” Level Streaming Volume์œผ๋กœ ์„œ๋ธŒ๋ ˆ๋ฒจ์„ ๋กœ๋“œ/์–ธ๋กœ๋“œํ•˜๋ฉด์„œ stat gc์™€ stat memory์˜ ๋ณ€ํ™”๋ฅผ ๊ด€์ฐฐํ•˜์„ธ์š”. ๋ ˆ๋ฒจ ์–ธ๋กœ๋“œ ํ›„ GC๊ฐ€ ์™„๋ฃŒ๋˜๊ธฐ๊นŒ์ง€์˜ ์‹œ๊ฐ„๊ณผ ํ•ด์ œ๋˜๋Š” ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์ธก์ •ํ•˜์„ธ์š”.

์‹ค์Šต 2: FlushLevelStreaming๊ณผ GC ํƒ€์ด๋ฐ ์ œ์–ด

UGameplayStatics::FlushLevelStreaming()๊ณผ ForceGarbageCollection()์˜ ์กฐํ•ฉ์œผ๋กœ ๋ ˆ๋ฒจ ์ „ํ™˜ ์‹œ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์™„์ „ํžˆ ์ •๋ฆฌํ•˜๋Š” ํŒจํ„ด์„ ๊ตฌํ˜„ํ•˜์„ธ์š”. ๋กœ๋”ฉ ํ™”๋ฉด ์ค‘์— GC๋ฅผ ์ง‘์ค‘ ์‹คํ–‰ํ•˜์—ฌ ๊ฒŒ์ž„ํ”Œ๋ ˆ์ด ์ค‘ ํžˆ์น˜๋ฅผ ๋ฐฉ์ง€ํ•˜์„ธ์š”.

์‹ฌํ™” ๊ณผ์ œ: ๋Œ€๊ทœ๋ชจ ์˜คํ”ˆ์›”๋“œ GC ์ตœ์ ํ™” ์ „๋žต

World Partition ๊ธฐ๋ฐ˜ ์˜คํ”ˆ์›”๋“œ์—์„œ ์…€ ๋กœ๋“œ/์–ธ๋กœ๋“œ์— ๋”ฐ๋ฅธ GC ๋ถ€ํ•˜๋ฅผ ์ตœ์ ํ™”ํ•˜์„ธ์š”. ํ”„๋ฆฌ๋กœ๋”ฉ, ์—์…‹ ํด๋Ÿฌ์Šคํ„ฐ๋ง, ์ ์ง„์  ์–ธ๋กœ๋“œ, GC ํƒ€์ด๋ฐ ์กฐ์ ˆ์„ ์กฐํ•ฉํ•˜์—ฌ ์‹ฌ๋ฆฌ์Šค ์ŠคํŠธ๋ฆฌ๋ฐ ํ™˜๊ฒฝ์—์„œ ํžˆ์น˜ ์—†๋Š” GC๋ฅผ ๊ตฌํ˜„ํ•˜์„ธ์š”.