관리 메뉴

기억을 위한 기록들

[UE] FGCObject에 관하여 본문

UnrealEngine

[UE] FGCObject에 관하여

에드윈H 2025. 11. 11. 16:01

FGCObject란 언리얼 엔진의 가비지 컬렉션(이하 GC) 시스템에게 "이 UObject는 내가 가지고 있으니 지우지 마"라고 알려주는 인터페이스이다.

UPROPERTY()가 없이 보관해야 할 경우 GC가 모르게 들고 있다가 크래시나는 문제를 해결하는 안전한 방법이다.

 

 

언리얼엔진의 GC는 UObject를 자동으로 추적하지는 않는다.

GC가 자동으로 추적하는 경우는 다음과 같다.

  • 리플렉션 시스템에 등록된 객체일 경우
  • RootSet에 등록 된 경우

 

문제는 다음과 같은 경우들에서 발생한다.

  • 일반 C++ 클래스에서 UObject* 포인터를 저장할 경우
  • TSharedPtr안에서 UObject 넣어야 할 경우
  • 커스텀으로 사용하는 UObjectPoolingManager 처럼 GC 외부에서 관리하는 경우

GC 입장에서는 이렇게 생각한다:

“어? 이 UObject를 참조하는 곳이 없네? → 처리!”

 

그리고 포인터는 dangling pointer(죽은 포인터) 가 되고,
사용하는 순간 크래시로 이어진다.

-> 이때 필요한 것이 FGCObject.

 

 

문제 상황 예시 : Non-UObject 클래스가 UObject를 저장할 경우

class FMyManager
{
public:
    UObject* CachedObj;  // 위험! GC가 모름
};

 

 

해결 상황 : FGCObject를 상속받고, AddReferencedObjects 함수 구현

class FMyManager : public FGCObject
{
public:
    UObject* CachedObj = nullptr;

    virtual void AddReferencedObjects(FReferenceCollector& Collector) override
    {
        Collector.AddReferencedObject(CachedObj);
    }

    virtual FString GetReferencerName() const override
    {
        return TEXT("FMyManager");
    }
};

 

이제 언리얼 GC는 다음과 같이 인식한다:

"CachedObj 객체는 참조되고 있으니, 제거하면 안 되겠다"

 

 

응용 : 풀에 있는 개체가 GC에 수거되지 않는다. 풀링 시스템에서도 안전하게 객체를 재사용할 수 있다.

class FObjectPool : public FGCObject
{
public:
    TArray<UObject*> Pool;

    virtual void AddReferencedObjects(FReferenceCollector& Collector) override
    {
        Collector.AddReferencedObjects(Pool);
    }
};

 

 

결론

 

FGCObject가 중요한 경우

  • Non-UObject 클래스에서 UObject를 들고 있어야 할 때
  • UObject Pooling, 싱글톤 매니저 등에서 GC 대상 제외가 필요할 때
  • UPROPERTY를 붙일 수 없는 곳에서 안전하게 UObject를 관리하려고 할 때

 

UPROPERTY가 안 된다면 FGCObject를 고려해야 한다.