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

Reflection ์‹œ์Šคํ…œ

UClass, FProperty, UFunction, ๋ฆฌํ”Œ๋ ‰์…˜ ๋งคํฌ๋กœ๊ฐ€ GC ์ฐธ์กฐ ์ถ”์ ์— ์–ด๋–ป๊ฒŒ ํ™œ์šฉ๋˜๋Š”์ง€ ๋ถ„์„ํ•ฉ๋‹ˆ๋‹ค

SECTION 01

UClass์™€ ํƒ€์ž… ์‹œ์Šคํ…œ

UObject์˜ ํƒ€์ž… ์ •๋ณด๋ฅผ ๋‹ด๋Š” UClass์˜ ๊ตฌ์กฐ

UClass ๊ณ„์ธต ๊ตฌ์กฐ

UClass๋Š” ๋ชจ๋“  UObject ํŒŒ์ƒ ํด๋ž˜์Šค์˜ ํƒ€์ž… ์ •๋ณด๋ฅผ ๋‹ด๋Š” ๋ฉ”ํƒ€ ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค. GC๋Š” UClass์˜ ํ”„๋กœํผํ‹ฐ ์ •๋ณด๋ฅผ ํ†ตํ•ด ๊ฐ์ฒด ๊ฐ„ ์ฐธ์กฐ ๊ด€๊ณ„๋ฅผ ์ž๋™์œผ๋กœ ์ถ”์ ํ•ฉ๋‹ˆ๋‹ค.

ํด๋ž˜์Šค ๊ณ„์ธต UObjectBase โ””โ”€โ”€ UObjectBaseUtility โ””โ”€โ”€ UObject โ””โ”€โ”€ UField (UE4, deprecated in UE5) โ”œโ”€โ”€ UStruct โ”‚ โ”œโ”€โ”€ UClass โ† ํด๋ž˜์Šค ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ โ”‚ โ”œโ”€โ”€ UScriptStruct โ† USTRUCT ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ โ”‚ โ””โ”€โ”€ UFunction โ† UFUNCTION ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ โ””โ”€โ”€ UEnum โ† UENUM ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ // UE5์—์„œ๋Š” FField ์‹œ์Šคํ…œ์œผ๋กœ ์ด์ „ FField โ””โ”€โ”€ FProperty โ† ํ”„๋กœํผํ‹ฐ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ (UProperty ๋Œ€์ฒด) โ”œโ”€โ”€ FObjectProperty โ† UObject* ์ฐธ์กฐ ์ถ”์ ! โ”œโ”€โ”€ FObjectPtrProperty โ† TObjectPtr ์ฐธ์กฐ ์ถ”์  โ”œโ”€โ”€ FWeakObjectProperty โ† TWeakObjectPtr โ”œโ”€โ”€ FSoftObjectProperty โ† TSoftObjectPtr โ”œโ”€โ”€ FArrayProperty โ† TArray ๋‚ด๋ถ€ ์ถ”์  โ”œโ”€โ”€ FMapProperty โ† TMap ๋‚ด๋ถ€ ์ถ”์  โ””โ”€โ”€ FStructProperty โ† ๊ตฌ์กฐ์ฒด ๋‚ด๋ถ€ ์ถ”์ 
GC์™€ ๋ฆฌํ”Œ๋ ‰์…˜์˜ ํ•ต์‹ฌ ๊ด€๊ณ„

GC๋Š” UPROPERTY()๋กœ ๋งˆํ‚น๋œ ํ”„๋กœํผํ‹ฐ๋งŒ ์ถ”์ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๋ฆฌํ”Œ๋ ‰์…˜ ์‹œ์Šคํ…œ์ด ํ•ด๋‹น ํ”„๋กœํผํ‹ฐ์˜ FProperty ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. UPROPERTY๊ฐ€ ์—†๋Š” raw UObject*๋Š” GC๊ฐ€ ์ธ์‹ํ•˜์ง€ ๋ชปํ•ด ๋Œ•๊ธ€๋ง ํฌ์ธํ„ฐ์˜ ์›์ธ์ด ๋ฉ๋‹ˆ๋‹ค.

SECTION 02

FProperty์™€ GC ์ฐธ์กฐ ์ถ”์ 

ํ”„๋กœํผํ‹ฐ ์‹œ์Šคํ…œ์ด GC ์ฐธ์กฐ๋ฅผ ์ž๋™์œผ๋กœ ์ถ”์ ํ•˜๋Š” ์›๋ฆฌ

FProperty์—์„œ FObjectProperty๋กœ

UE5์—์„œ UProperty๋Š” FProperty๋กœ ๋Œ€์ฒด๋˜์—ˆ์Šต๋‹ˆ๋‹ค. FProperty๋Š” UObject๊ฐ€ ์•„๋‹ˆ๋ฏ€๋กœ GC ๋Œ€์ƒ์ด ์•„๋‹ˆ๋ฉฐ, ๋ฉ”๋ชจ๋ฆฌ ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ์ค„์—ˆ์Šต๋‹ˆ๋‹ค. GC๋Š” FObjectProperty ํƒ€์ž…์˜ ํ”„๋กœํผํ‹ฐ๋ฅผ ํ†ตํ•ด UObject ์ฐธ์กฐ๋ฅผ ์ถ”์ ํ•ฉ๋‹ˆ๋‹ค.

C++ // GC์˜ ์ฐธ์กฐ ์ถ”์  ํ•ต์‹ฌ ํ•จ์ˆ˜ (๊ฐ„๋žตํ™”) void UClass::AssembleReferenceTokenStream() { // ํด๋ž˜์Šค์˜ ๋ชจ๋“  FProperty๋ฅผ ์ˆœํšŒ for (FProperty* Prop = PropertyLink; Prop; Prop = Prop->PropertyLinkNext) { // UObject ์ฐธ์กฐ ํ”„๋กœํผํ‹ฐ์ธ์ง€ ํ™•์ธ if (Prop->ContainsObjectReference()) { // GC ํ† ํฐ ์ŠคํŠธ๋ฆผ์— ์ถ”๊ฐ€ Prop->EmitReferenceInfo(*this, ReferenceTokenStream); } } } // GC ์ˆœํšŒ ์‹œ ํ† ํฐ ์ŠคํŠธ๋ฆผ์„ ์‚ฌ์šฉํ•˜์—ฌ // ๊ฐ์ฒด ๋‚ด๋ถ€์˜ ๋ชจ๋“  UObject* ์ฐธ์กฐ๋ฅผ ๋น ๋ฅด๊ฒŒ ์ˆ˜์ง‘ void ProcessObjectArray(FGCArrayStruct& ArrayStruct) { for (auto& Token : ArrayStruct.ReferenceTokenStream) { UObject** ObjRef = Token.GetObjectRef(Object); if (*ObjRef) HandleObjectReference(*ObjRef); // Reachable ๋งˆํ‚น } }

์ฐธ์กฐ ํ† ํฐ ์ŠคํŠธ๋ฆผ์˜ ๊ตฌ์กฐ

ํ† ํฐ ํƒ€์ž… ๋Œ€์ƒ ํ”„๋กœํผํ‹ฐ ์„ค๋ช…
GCRT_Object UObject* ๋‹จ์ผ ๊ฐ์ฒด ์ฐธ์กฐ
GCRT_ArrayObject TArray<UObject*> ๋ฐฐ์—ด ๋‚ด ๊ฐ์ฒด ์ฐธ์กฐ๋“ค
GCRT_ArrayStruct TArray<FMyStruct> ๊ตฌ์กฐ์ฒด ๋ฐฐ์—ด ๋‚ด๋ถ€ ์ฐธ์กฐ
GCRT_ExternalPackage ์™ธ๋ถ€ ํŒจํ‚ค์ง€ ํŒจํ‚ค์ง€ ๊ฐ„ ์ฐธ์กฐ
GCRT_AddReferencedObjects ์ปค์Šคํ…€ ์ˆ˜๋™ ์ฐธ์กฐ ๋“ฑ๋ก ์ฝœ๋ฐฑ
SECTION 03

UFunction๊ณผ ๋ฆฌํ”Œ๋ ‰์…˜ ๋งคํฌ๋กœ

UCLASS, UPROPERTY, UFUNCTION ๋งคํฌ๋กœ์˜ GC ๊ด€๋ จ ์—ญํ• 

๋ฆฌํ”Œ๋ ‰์…˜ ๋งคํฌ๋กœ์™€ UHT

Unreal Header Tool(UHT)์€ ๋ฆฌํ”Œ๋ ‰์…˜ ๋งคํฌ๋กœ๋ฅผ ํŒŒ์‹ฑํ•˜์—ฌ .generated.h์™€ .gen.cpp ํŒŒ์ผ์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ด ํŒŒ์ผ๋“ค์— GC๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ์ฐธ์กฐ ํ† ํฐ ์ŠคํŠธ๋ฆผ ๊ตฌ์ถ• ์ฝ”๋“œ๊ฐ€ ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.

C++ // ์›๋ณธ ํ—ค๋” UCLASS() class UMyObject : public UObject { GENERATED_BODY() UPROPERTY() UObject* TrackedRef; // GC๊ฐ€ ์ถ”์ ํ•จ! UObject* UntrackedRef; // GC๊ฐ€ ๋ชจ๋ฆ„! ์œ„ํ—˜! UPROPERTY() TArray<UObject*> TrackedArray; // ๋ฐฐ์—ด ๋‚ด๋ถ€๋„ ์ถ”์  UPROPERTY() TMap<FName, UObject*> TrackedMap; // ๋งต Value๋„ ์ถ”์  UFUNCTION() void MyFunction(); // ํ•จ์ˆ˜ ํŒŒ๋ผ๋ฏธํ„ฐ์˜ UObject*๋„ GC ๊ณ ๋ ค }; // UHT๊ฐ€ ์ƒ์„ฑํ•˜๋Š” ์ฝ”๋“œ (MyObject.gen.cpp, ๊ฐ„๋žตํ™”) void UMyObject::StaticRegisterNativesUMyObject() { // ๋„ค์ดํ‹ฐ๋ธŒ ํ•จ์ˆ˜ ๋“ฑ๋ก } const UECodeGen_Private::FObjectPropertyParams Z_Construct_UClass_UMyObject_Statics::NewProp_TrackedRef = { "TrackedRef", nullptr, // RepNotifyFunc CPF_None, UECodeGen_Private::EPropertyGenFlags::Object, // ... offset, class ์ •๋ณด ๋“ฑ };
UPROPERTY() ์—†๋Š” UObject* ์ฐธ์กฐ์˜ ์œ„ํ—˜

UPROPERTY() ๋งคํฌ๋กœ๊ฐ€ ์—†๋Š” UObject* ๋ฉค๋ฒ„ ๋ณ€์ˆ˜๋Š” ๋ฆฌํ”Œ๋ ‰์…˜ ์ •๋ณด๊ฐ€ ์ƒ์„ฑ๋˜์ง€ ์•Š์•„ GC ํ† ํฐ ์ŠคํŠธ๋ฆผ์— ํฌํ•จ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ฒฐ๊ณผ์ ์œผ๋กœ:

  • ์ฐธ์กฐ๋œ ๊ฐ์ฒด๊ฐ€ GC์— ์˜ํ•ด ์ˆ˜์ง‘๋  ์ˆ˜ ์žˆ์Œ (๋Œ•๊ธ€๋ง ํฌ์ธํ„ฐ)
  • ํ•ด๋‹น ํฌ์ธํ„ฐ ์‚ฌ์šฉ ์‹œ ํฌ๋ž˜์‹œ ๋ฐœ์ƒ ๊ฐ€๋Šฅ
  • ๋””๋ฒ„๊น…์ด ๋งค์šฐ ์–ด๋ ค์›€ (๊ฐ„ํ—์  ๋ฐœ์ƒ)
SECTION 04

USTRUCT์™€ ์ค‘์ฒฉ ์ฐธ์กฐ ์ถ”์ 

๊ตฌ์กฐ์ฒด ๋‚ด๋ถ€์˜ UObject ์ฐธ์กฐ๋ฅผ GC๊ฐ€ ์ถ”์ ํ•˜๋Š” ๋ฐฉ๋ฒ•

USTRUCT ๋‚ด๋ถ€์˜ ์ฐธ์กฐ ์ถ”์ 

USTRUCT๋กœ ์„ ์–ธ๋œ ๊ตฌ์กฐ์ฒด ๋‚ด๋ถ€์— UPROPERTY๋กœ ๋งˆํ‚น๋œ UObject*๊ฐ€ ์žˆ์œผ๋ฉด, GC๋Š” ๊ตฌ์กฐ์ฒด๋ฅผ ํฌํ•จํ•˜๋Š” ์™ธ๋ถ€ ๊ฐ์ฒด์˜ ํ† ํฐ ์ŠคํŠธ๋ฆผ์— ์ด๋ฅผ ํฌํ•จ์‹œ์ผœ ์ถ”์ ํ•ฉ๋‹ˆ๋‹ค.

C++ USTRUCT() struct FMyData { GENERATED_BODY() UPROPERTY() UObject* InnerRef; // ๊ตฌ์กฐ์ฒด ๋‚ด๋ถ€ ์ฐธ์กฐ๋„ ์ถ”์ ๋จ UPROPERTY() TArray<UTexture2D*> Textures; // ๋ฐฐ์—ด ๋‚ด๋ถ€๋„ ์ถ”์  }; UCLASS() class UMyContainer : public UObject { GENERATED_BODY() UPROPERTY() FMyData Data; // ๊ตฌ์กฐ์ฒด ์ž์ฒด๊ฐ€ UPROPERTY์ด๋ฉด ๋‚ด๋ถ€ ์ฐธ์กฐ ์ถ”์  UPROPERTY() TArray<FMyData> DataArray; // ๋ฐฐ์—ด ๋‚ด ๊ตฌ์กฐ์ฒด์˜ ์ฐธ์กฐ๋„ ์ถ”์  FMyData NoTrackData; // UPROPERTY ์—†์Œ โ†’ ๋‚ด๋ถ€ ์ฐธ์กฐ ๋ฏธ์ถ”์ ! };
์ค‘์ฒฉ ์ถ”์ ์˜ ์กฐ๊ฑด

GC๊ฐ€ ๊ตฌ์กฐ์ฒด ๋‚ด๋ถ€ ์ฐธ์กฐ๋ฅผ ์ถ”์ ํ•˜๋ ค๋ฉด ์„ธ ๊ฐ€์ง€ ์กฐ๊ฑด์ด ๋ชจ๋‘ ์ถฉ์กฑ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค:

  • ๊ตฌ์กฐ์ฒด๊ฐ€ USTRUCT()๋กœ ์„ ์–ธ๋˜์–ด์•ผ ํ•จ
  • ๊ตฌ์กฐ์ฒด ๋‚ด๋ถ€ ๋ฉค๋ฒ„๊ฐ€ UPROPERTY()๋กœ ๋งˆํ‚น๋˜์–ด์•ผ ํ•จ
  • ์™ธ๋ถ€ ํด๋ž˜์Šค์—์„œ ๊ตฌ์กฐ์ฒด ๋ณ€์ˆ˜๊ฐ€ UPROPERTY()๋กœ ๋งˆํ‚น๋˜์–ด์•ผ ํ•จ
SUMMARY

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

์ด ๊ฐ•์˜์—์„œ ๋ฐฐ์šด ๋‚ด์šฉ
  • UClass๋Š” FProperty ๋ชฉ๋ก์„ ํ†ตํ•ด GC ์ฐธ์กฐ ํ† ํฐ ์ŠคํŠธ๋ฆผ์„ ๊ตฌ์ถ•ํ•ฉ๋‹ˆ๋‹ค
  • UE5์—์„œ FProperty๋Š” UObject๊ฐ€ ์•„๋‹Œ ๊ฒฝ๋Ÿ‰ ๊ฐ์ฒด๋กœ, GC ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ์ค„์—ˆ์Šต๋‹ˆ๋‹ค
  • UPROPERTY() ๋งคํฌ๋กœ๊ฐ€ ์—†๋Š” UObject* ์ฐธ์กฐ๋Š” GC๊ฐ€ ์ถ”์ ํ•˜์ง€ ๋ชปํ•ด ๋Œ•๊ธ€๋ง ํฌ์ธํ„ฐ์˜ ์›์ธ์ด ๋ฉ๋‹ˆ๋‹ค
  • UHT๋Š” ๋ฆฌํ”Œ๋ ‰์…˜ ๋งคํฌ๋กœ๋ฅผ ํŒŒ์‹ฑํ•˜์—ฌ .gen.cpp์— GC ํ† ํฐ ์ŠคํŠธ๋ฆผ ๊ตฌ์ถ• ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค
  • USTRUCT ๋‚ด๋ถ€ ์ฐธ์กฐ ์ถ”์ ์€ ๊ตฌ์กฐ์ฒด์™€ ๋ฉค๋ฒ„ ๋ชจ๋‘ UPROPERTY()๊ฐ€ ์žˆ์–ด์•ผ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค
PRACTICE

๋„์ „ ๊ณผ์ œ

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

์‹ค์Šต 1: UPROPERTY ๋ฆฌํ”Œ๋ ‰์…˜์œผ๋กœ ์ฐธ์กฐ ํƒ์ƒ‰

UClass::ForEachProperty๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํŠน์ • UObject ์ธ์Šคํ„ด์Šค์˜ ๋ชจ๋“  UPROPERTY ์ค‘ UObject* ํƒ€์ž…์ธ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ฐพ์•„ ์ฐธ์กฐ ๊ทธ๋ž˜ํ”„๋ฅผ ์ถœ๋ ฅํ•˜์„ธ์š”. FObjectPropertyBase๋ฅผ ํ™œ์šฉํ•˜์—ฌ ํฌ์ธํ„ฐ ๊ฐ’์„ ์ฝ์–ด๋ณด์„ธ์š”.

์‹ค์Šต 2: FProperty ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ๋ถ„์„

์ปค์Šคํ…€ UObject ํด๋ž˜์Šค์— ๋‹ค์–‘ํ•œ UPROPERTY ์ง€์ •์ž(EditAnywhere, BlueprintReadWrite, Transient ๋“ฑ)๋ฅผ ์ ์šฉํ•˜๊ณ , StaticClass()->PropertyLink๋ฅผ ์ˆœํšŒํ•˜๋ฉฐ ๊ฐ FProperty์˜ PropertyFlags๋ฅผ ๋ถ„์„ํ•˜์„ธ์š”.

์‹ฌํ™” ๊ณผ์ œ: ๋ฆฌํ”Œ๋ ‰์…˜ ๊ธฐ๋ฐ˜ GC ์ฐธ์กฐ ์‹œ๊ฐํ™”

FReferenceChainSearch๋ฅผ ํ™œ์šฉํ•˜์—ฌ ํŠน์ • UObject์— ๋Œ€ํ•œ ์ฐธ์กฐ ์ฒด์ธ์„ ์ถ”์ ํ•˜๊ณ , ๊ฒฐ๊ณผ๋ฅผ ๊ตฌ์กฐํ™”๋œ ํ…์ŠคํŠธ๋กœ ์ถœ๋ ฅํ•˜๋Š” ๋””๋ฒ„๊ทธ ์œ ํ‹ธ๋ฆฌํ‹ฐ ํ•จ์ˆ˜๋ฅผ ์ž‘์„ฑํ•˜์„ธ์š”. obj refs ์ฝ˜์†” ๋ช…๋ น์–ด์˜ ๊ฒฐ๊ณผ์™€ ๋น„๊ตํ•ด๋ณด์„ธ์š”.