UObject

  • UObject는 Unreal Engine에서 가장 기본이 되는 객체다
  • UCLASS 매크로 선언으로 UObject를 관리하는 시스템이 이를 인식한다
    • Reflection System을 통해 Garbage Collection을 수행하는 등의 역할
// ...
// Unreal Header Tool이 빌드 시 자동 생성
#include "MyObject.generated.h"

// 클래스를 리플렉션 시스템에 등록한다
UCLASS()
// MYPROJECT_API 매크로는 해당 클래스의 기능을 다른 모듈에서 쓸 수 있게 해준다
// 요게 없으면 다른 모듈에서 사용 시 심볼을 Link할 수 없어서 Link 에러가 발생한다
class MYPROJECT_API UMyObject : public UObject
{
  // MyObject.generated.h에서 이 매크로를 정의한다
  GENERATED_BODY()
};

// 오브젝트 생성
UMyObject* MyObject = NewObject<UMyObject>();

// Component 생성
UMyObject::UMyObject()
{
  MyActorComponent = CreateDefaultComponent<UMyActorComponent>(TEXT("MyActorComponent"));
}

// Actor 생성
// ...
AActor* MyActor = GetWorld()->SpawnActor<UMyActor>(SpawnInfo);

UObject의 생성 및 삭제 시점

생성 시점

  1. NewObject로 새로운 UObject 인스턴스 생성 시
  2. Actor Spawn이나 Component의 CreateComponent 등

삭제 시점

  1. 해당 객체의 Strong Reference 객체가 존재하지 않을 때, GC Tick에서 Delete
  2. Actor Destroy, ActorComponent의 DestroyComponent 등 명시적 호출
  3. Level이 Destroy될 때 잠초중인 객체들 삭제

Class Default Object

  • 각 UCLASS는 CDO라는 하나의 오브젝트 객체를 유지
  • CDO는 생성자에 의해 생성된 이후, 수정되지 않는 탬플릿 용도의 오브젝트
  • Read-Only지만, GetClass() 메서드를 통해 접근 가능

Garbage Collector

  • Reference Graph를 만들어서 오브젝트들이 Graph의 Root로부터 참조 여부를 검사한다
  • 연결되지 않았다고 판단된 오브젝트들은 모두 GC 대상이 된다

Object를 생성하는 방법

UCLASS()
class MYPROJECT_API UMyObject : public UObject
{
	GENERATED_BODY()
  // ...
};

// 가장 일반적인 방법이다
UMyObject* Object2 = NewObject<UMyObject>();

// 아래 방법은 new operator를 overload해야 한다
UMyObject* Object1 = new UMyObject();

// 아래 방법은 4.8 부터 deprecated 되었다
UMyObject* Object3 = NewNamedObject<UMyObject>();
UMyObject* Object4 = ConstructObject<UMyObject>();

UObject는 언제 삭제되는가?

  1. 엔진이 더 이상 해당 Object를 참조하지 않을 때, Garbage Collection System에 의해 소멸처리 된다
    • 마지막으로 참조하던 포인터가 null이 되는 순간
  2. Strong Reference를 갖지 않는 Actor에 대해 발생한다
  3. MarkPendingKill
    • 위 함수는 더 이상 사용하지 않고, PendingKill 기능이 활성화되어 있다면 MarkAsGarbage가 유사한 방식으로 작동하여 대체한다
    • 어떤 Object로의 Reference를 모두 null로 만든다
    • 다음 Garbage Collection 때 이 Object를 소멸 처리한다

MarkAsGarbage(), IsValid()의 동작 방식

  • MarkAsGarbage
    • PendingKill 기능이 활성화 되어 있다면 MarkPendingKill와 유사한 방식으로 동작한다
    • bPendingKillDisabled는 GPendingKillEnabled의 역 값이며, 이 값이 true인 경우 Garbage Collection에 의해 자동으로 null 처리되지 않는다
    • 어떤 Object로의 reference를 모두 null로 만든다
    • 다음 Garbage Collection이 작동할 때, 이 Object를 소멸한다
  • IsValid
    • 인자로 받은 Pointer가 현재 사용되는 Object를 가리키고 있는지 확인
    • Reference Graph에서 탐색하고 결과값이 존재하는지 여부를 bool 값으로 반환

IsValid()와 IsVAalidLowLevel()의 차이점

  • IsValid는 Object Pointer가 null 여부 및 Garbage collection 대상 여부인지를 확인
  • IsValidLowLevel은 IsValid와 동일한 null check를 수행하지만 extra check를 수행한다
    • this == nullptr -> null 상태인지 확인
    • !ClassPrivate -> Reflection System에 올바르게 등록되었는지 확인
    • GUObjectArray.IsValid(this) -> GUObjectArray에서 정상적인 index를 갖고 있는지, 즉 범위 안에 있는지 혹은 해당 index가 다른 Object로 override된 상태가 아닌지 확인

DefaultSubobject란?

  • Subobject란 Actor를 구성하는 Component를 의미한다
    • 부모 Actor에 할당되는 자식 Actor 역시 ChildActorComponent로 분류한다
  • 부모 Actor가 생성 및 초기화하면서 자동으로 생성되는 Component들 역시, 생성된 이후 Default 값으로 초기화된 상태로 부모 Actor에 Attach 된다

Actor vs. Object

Actor

  • AActor에서 파생된 클래스
  • Actor는 그 자체로 하나의 완전하고 독립된 형태의 게임 오브젝트 단위
  • World 및 레벨에 배치할 수 있는 게임 오브젝트
// World.h
class UWorld
{
  // ...
  /** Persistent level containing the world info, default brush and actors spawned during gameplay among other things	*/
  UPROPERTY(Transient)
	TObjectPtr<class ULevel> PersistentLevel;
  // ...
}

// Level.h
class ULevel
{
  // ...
  /** Array of all actors in this level, used by FActorIteratorBase and derived classes */
  TArray<TObjectPtr<AActor>> Actors;

  /** Array of actors to be exposed to GC in this level. All other actors will be referenced through ULevelActorContainer */
  TArray<TObjectPtr<AActor>> ActorsForGC;
  // ...
}
  • UWorld -> PersistentLevel에서 관리한다
  • Actor Cluster 생성 여부에 따라 ActorsForGC 또는 Actors 리스트로 분류된다

Object

  • UObject에서 파생된 클래스
  • Object는 특정 요소가 강조된 일부 혹은 부분 단위
    • Component가 Object를 상속하고, Actor를 구성하는 역할을 한다는 데에서 생각해보면…

출처

Categories: ,

Updated: