3 분 소요

언리얼 엔진의 가비지 컬렉터

언리얼 엔진은 UObject에 대한 객체 관리를
자동으로 해주며 프로그래머가 직접 메모리를 해제하지 않아도
엔진 영역에서 메모리를 관리해 준다

  • GC(Garbage Collection)?
    더 이상 사용되지 않는 객체(데이터)를 자동으로 찾아
    메모리에서 제거하는 시스템을 말함
    C,C++ 처럼 수동으로 메모리 관리를 해주는 언어가 아니면
    대부분 GC가 메모리 관리를 대신해준다

작동 방식

언리얼 GC는 Mark and Sweep 알고리즘 기반

  1. Mark (표시) 단계
    • GC가 Root 객체들에서 시작해, ‘연결’된 객체들을 추적
    • UObject 중 UPROPERTY() 매크로로 마킹된 포인터를 추적
    • ‘사용 중’인 객체를 모두 mark 한다
  2. Sweep (청소) 단계
    • 표시되지 않은 객체들을 ‘사용하지 않는다고 간주’하고 파괴(destroy)
    • 메모리도 같이 해제

참고 매크로 & 함수

항목 설명
UPROPERTY() GC가 추적할 수 있도록 포인터를 표시합니다. 이걸 안 하면 객체가 GC 대상이 됩니다.
AddToRoot() 객체를 GC 루트로 강제 등록해서 영구적으로 유지합니다. (보통은 권장되지 않음)
IsPendingKill() 객체가 GC에 의해 삭제 대기 중인지 확인할 때 사용해요.
CollectGarbage() 강제로 GC를 실행시키는 함수입니다 (주로 에디터나 개발 도중 테스트용).

유의할 점으로
UPROPERTY()를 붙이지 않으면
GC가 ‘참조 중’이라는 사실을 모르기에
해제 해 버릴 수 있다는 점

UPROPERTY() // 이거 안 붙이면 
UMyObject* MyObj; // 이걸 '참조'하는지 모르기에 메모리 해제 당할 수 있음

Root Set

언리얼 GC가 Mark 단계에서 ‘시작점’으로 삼는
UObject 집합들을 Root Set 이라 한다
(해당 집합에 있는 객체들은 ‘살아있는 객체’로 취급)

Root Set에 포함되는 조건들

포함 이유 설명
RF_RootSet 플래그 설정됨 AddToRoot() 호출 시 자동으로 설정
엔진 내부 루트로 등록됨 예: 게임 인스턴스, 월드 등
에디터나 런타임에서 참조 중 예: 뷰포트에 표시되는 액터 등
UPROPERTY()로 참조되고 있음 GC가 해당 객체를 “사용 중”으로 판단 가능

Unreal GC 동작 정리

결국 다음과 같은 방식으로 Unreal GC가 동작한다

  1. Root Set 시작
    • 해당 집합 개체 식별
    • ‘항상 살아 있는 객체’ 취급
      (ex : Player Controller, Engine 관련 객체)
  2. Mark 단계
    • Root Set 객체에서 시작
    • 직간접 참조하는 UObject들에 대한 마킹
      (객체가 사용중이라는 확인)
    • 즉, UPROPERTY()로 선언된 포인터만 따라간다
      (Reflection 시스템에 기반)
  3. Sweep 단계
    • 마킹 되지 않은 객체들의 메모리 회수
    • 소멸자 호출 및 메모리 반환
    • 파괴 순서
    • RF_BeginDestroyed 설정 -> BeginDestroy() 호출
    • 엔진에서 IsReadyForFinishDestroy() 체크
    • 준비 완료 시 RF_FinishDestroyed 설정 → FinishDestroy() 호출
    • 메모리 해제

Image

GUObjectArray 와 플래그?

GUObjectArray 는 Unreal Engine 내부에서
모든 UObject 인스턴스를 추적 및 관리하는
전역 객체 배열 이다

역할 설명
UObject의 전체 목록 저장 게임 내 모든 UObject의 생명주기를 추적
인덱스 기반 접근 지원 내부적으로 FObjectHandle/FObjectItem 등을 통해 빠른 검색
GC에서 핵심 역할 Mark & Sweep 시 전부 순회하며 GC 대상 여부 판단

GUObjectArray 내부의 FObjectItem 배열에서
각 객체의 EObjectFlags 플래그들을 관리한다
(FObjectItem 내부에서 플래그 관리)

주요 EObjectFlags 플래그

  • RF_RootSet
    객체를 GC의 Root Set에 포함
    AddToRoot() 호출 시 자동 설정
    반대로 RemoveFromRoot 호출 시 플래그 제거
  • RF_BeginDestroyed
    객체가 GC에 의하여 파괴 타켓이 됨
    이 플래그가 설정된 순간 ‘유효하지 않은’ 상태가 됨
    이 플래그 설정 후,BeginDestroy()가 호출된다
  • RF_FinishDestroyed
    객체가 완전히 파괴되었음을 나타냄
    메모리 해제 직전의 상태
    FinishDestroy()가 호출된 후, 설정
    • 함수 호출 직후, 바로 사라지는 것이 아니라
      메모리 해제를 기다리는 상황이며
      일정 시간 후, 해제되기에 설정하는 플래그

그 외에도
RF_ 플래그들이 존재
관련 공식 문서

Unreal의 리플렉션

UObject 기반의 클래스들을
엔진에서 읽을 수 있도록 클래스 타입을 공유하는 시스템

언리얼 내부의 동작하는 다양한 모듈도 UObject 기반
다만, 사용자가 정의한 ‘타입’을 엔진에서 알지 못하므로
이를 처리할 수 있도록 ‘타입 정보’를 공유해야 함
=> 이를 위하여 리플렉션이 필요

Image

  • 리플렉션 시스템?
    클래스, 함수, 변수 등에 대한 정보를 코드로부터 추출하고,
    런타임이나 에디터에서 사용 가능하게 만드는 시스템

UHT (Unreal Header Tool)

Unreal Build Tool(UBT)의 일부로서
UCLASS/USTRUCT/UPROPERTY/UFUNCTION 등을
파싱해서 메타데이터 코드를 자동 생성하는 툴

  • 헤더 파일에서 UCLASS(), UPROPERTY(), UFUNCTION() 등을 파싱
  • .generated.h 파일을 생성
  • 해당 파일이 포함하는 것들
    • 클래스 등록 정보 (StaticClass(), StaticRegisterNatives())
    • 리플렉션 데이터 (FProperty, FFieldClass, MetaData, FieldPath 등)
    • 에디터/GC/블루프린트 호환용 메서드

Image

리플렉션 관련 매크로

매크로 리플렉션에서의 목적 일반적인 위치
UCLASS() C++ 클래스를 UObject 기반 리플렉션 시스템에 등록 클래스 정의 앞
UPROPERTY() 멤버 변수를 리플렉션 시스템에 노출 멤버 변수 선언 앞
UFUNCTION() 멤버 함수를 리플렉션 시스템에 노출 멤버 함수 선언 앞
USTRUCT() C++ 구조체를 리플렉션 시스템에 등록 구조체 정의 앞
GENERATED_BODY() UHT가 생성하는 리플렉션 및 엔진 지원 코드를 위한 삽입 지점 클래스/구조체 본문 첫 줄

정리

Image

요약하자면,
Unreal 리플렉션 시스템은
사용자가 만든 클래스를 UObject 기반의 엔진 시스템과
호환되도록 제공하는 메타데이터 기반의 인프라이다

(GC, Editor, BP, Serialization 등이 모두 이러한
엔진 기능이므로 이 들과 사용자 정의 클래스를 연결해준다)

댓글남기기