Reflection ์์คํ
UClass, FProperty, UFunction, ๋ฆฌํ๋ ์ ๋งคํฌ๋ก๊ฐ GC ์ฐธ์กฐ ์ถ์ ์ ์ด๋ป๊ฒ ํ์ฉ๋๋์ง ๋ถ์ํฉ๋๋ค
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๋ UPROPERTY()๋ก ๋งํน๋ ํ๋กํผํฐ๋ง ์ถ์ ํฉ๋๋ค. ์ด๋ ๋ฆฌํ๋ ์
์์คํ
์ด ํด๋น ํ๋กํผํฐ์ FProperty ๋ฉํ๋ฐ์ดํฐ๋ฅผ ์์ฑํ๊ธฐ ๋๋ฌธ์
๋๋ค. UPROPERTY๊ฐ ์๋ raw UObject*๋ GC๊ฐ ์ธ์ํ์ง ๋ชปํด ๋๊ธ๋ง ํฌ์ธํฐ์ ์์ธ์ด ๋ฉ๋๋ค.
FProperty์ GC ์ฐธ์กฐ ์ถ์
ํ๋กํผํฐ ์์คํ ์ด GC ์ฐธ์กฐ๋ฅผ ์๋์ผ๋ก ์ถ์ ํ๋ ์๋ฆฌ
FProperty์์ FObjectProperty๋ก
UE5์์ UProperty๋ FProperty๋ก ๋์ฒด๋์์ต๋๋ค. FProperty๋ UObject๊ฐ ์๋๋ฏ๋ก GC ๋์์ด ์๋๋ฉฐ, ๋ฉ๋ชจ๋ฆฌ ์ค๋ฒํค๋๊ฐ ์ค์์ต๋๋ค. GC๋ FObjectProperty ํ์
์ ํ๋กํผํฐ๋ฅผ ํตํด UObject ์ฐธ์กฐ๋ฅผ ์ถ์ ํฉ๋๋ค.
// 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 |
์ปค์คํ | ์๋ ์ฐธ์กฐ ๋ฑ๋ก ์ฝ๋ฐฑ |
UFunction๊ณผ ๋ฆฌํ๋ ์ ๋งคํฌ๋ก
UCLASS, UPROPERTY, UFUNCTION ๋งคํฌ๋ก์ GC ๊ด๋ จ ์ญํ
๋ฆฌํ๋ ์ ๋งคํฌ๋ก์ UHT
Unreal Header Tool(UHT)์ ๋ฆฌํ๋ ์
๋งคํฌ๋ก๋ฅผ ํ์ฑํ์ฌ .generated.h์ .gen.cpp ํ์ผ์ ์์ฑํฉ๋๋ค. ์ด ํ์ผ๋ค์ GC๊ฐ ์ฌ์ฉํ๋ ์ฐธ์กฐ ํ ํฐ ์คํธ๋ฆผ ๊ตฌ์ถ ์ฝ๋๊ฐ ํฌํจ๋ฉ๋๋ค.
// ์๋ณธ ํค๋
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* ๋ฉค๋ฒ ๋ณ์๋ ๋ฆฌํ๋ ์
์ ๋ณด๊ฐ ์์ฑ๋์ง ์์ GC ํ ํฐ ์คํธ๋ฆผ์ ํฌํจ๋์ง ์์ต๋๋ค. ๊ฒฐ๊ณผ์ ์ผ๋ก:
- ์ฐธ์กฐ๋ ๊ฐ์ฒด๊ฐ GC์ ์ํด ์์ง๋ ์ ์์ (๋๊ธ๋ง ํฌ์ธํฐ)
- ํด๋น ํฌ์ธํฐ ์ฌ์ฉ ์ ํฌ๋์ ๋ฐ์ ๊ฐ๋ฅ
- ๋๋ฒ๊น ์ด ๋งค์ฐ ์ด๋ ค์ (๊ฐํ์ ๋ฐ์)
USTRUCT์ ์ค์ฒฉ ์ฐธ์กฐ ์ถ์
๊ตฌ์กฐ์ฒด ๋ด๋ถ์ UObject ์ฐธ์กฐ๋ฅผ GC๊ฐ ์ถ์ ํ๋ ๋ฐฉ๋ฒ
USTRUCT ๋ด๋ถ์ ์ฐธ์กฐ ์ถ์
USTRUCT๋ก ์ ์ธ๋ ๊ตฌ์กฐ์ฒด ๋ด๋ถ์ UPROPERTY๋ก ๋งํน๋ UObject*๊ฐ ์์ผ๋ฉด, GC๋ ๊ตฌ์กฐ์ฒด๋ฅผ ํฌํจํ๋ ์ธ๋ถ ๊ฐ์ฒด์ ํ ํฐ ์คํธ๋ฆผ์ ์ด๋ฅผ ํฌํจ์์ผ ์ถ์ ํฉ๋๋ค.
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()๋ก ๋งํน๋์ด์ผ ํจ
ํต์ฌ ์์ฝ
- UClass๋ FProperty ๋ชฉ๋ก์ ํตํด GC ์ฐธ์กฐ ํ ํฐ ์คํธ๋ฆผ์ ๊ตฌ์ถํฉ๋๋ค
- UE5์์ FProperty๋ UObject๊ฐ ์๋ ๊ฒฝ๋ ๊ฐ์ฒด๋ก, GC ์ค๋ฒํค๋๊ฐ ์ค์์ต๋๋ค
- UPROPERTY() ๋งคํฌ๋ก๊ฐ ์๋ UObject* ์ฐธ์กฐ๋ GC๊ฐ ์ถ์ ํ์ง ๋ชปํด ๋๊ธ๋ง ํฌ์ธํฐ์ ์์ธ์ด ๋ฉ๋๋ค
- UHT๋ ๋ฆฌํ๋ ์ ๋งคํฌ๋ก๋ฅผ ํ์ฑํ์ฌ .gen.cpp์ GC ํ ํฐ ์คํธ๋ฆผ ๊ตฌ์ถ ์ฝ๋๋ฅผ ์์ฑํฉ๋๋ค
- USTRUCT ๋ด๋ถ ์ฐธ์กฐ ์ถ์ ์ ๊ตฌ์กฐ์ฒด์ ๋ฉค๋ฒ ๋ชจ๋ UPROPERTY()๊ฐ ์์ด์ผ ๋์ํฉ๋๋ค
๋์ ๊ณผ์
๋ฐฐ์ด ๋ด์ฉ์ ์ง์ ์ค์ตํด๋ณด์ธ์
UClass::ForEachProperty๋ฅผ ์ฌ์ฉํ์ฌ ํน์ UObject ์ธ์คํด์ค์ ๋ชจ๋ UPROPERTY ์ค UObject* ํ์ ์ธ ํ๋กํผํฐ๋ฅผ ์ฐพ์ ์ฐธ์กฐ ๊ทธ๋ํ๋ฅผ ์ถ๋ ฅํ์ธ์. FObjectPropertyBase๋ฅผ ํ์ฉํ์ฌ ํฌ์ธํฐ ๊ฐ์ ์ฝ์ด๋ณด์ธ์.
์ปค์คํ UObject ํด๋์ค์ ๋ค์ํ UPROPERTY ์ง์ ์(EditAnywhere, BlueprintReadWrite, Transient ๋ฑ)๋ฅผ ์ ์ฉํ๊ณ , StaticClass()->PropertyLink๋ฅผ ์ํํ๋ฉฐ ๊ฐ FProperty์ PropertyFlags๋ฅผ ๋ถ์ํ์ธ์.
FReferenceChainSearch๋ฅผ ํ์ฉํ์ฌ ํน์ UObject์ ๋ํ ์ฐธ์กฐ ์ฒด์ธ์ ์ถ์ ํ๊ณ , ๊ฒฐ๊ณผ๋ฅผ ๊ตฌ์กฐํ๋ ํ ์คํธ๋ก ์ถ๋ ฅํ๋ ๋๋ฒ๊ทธ ์ ํธ๋ฆฌํฐ ํจ์๋ฅผ ์์ฑํ์ธ์. obj refs ์ฝ์ ๋ช ๋ น์ด์ ๊ฒฐ๊ณผ์ ๋น๊ตํด๋ณด์ธ์.