[이득우의 언리얼] 12. 언리얼 엔진의 메모리 관리

2026. 2. 9. 14:12·기타/[강의] 이득우의 언리얼 프로그래밍 Part1

개요

이번 강의에서는 Unreal Engine의 가비지 컬렉션(Garbage Collection) 시스템을 이해하고, UObject 포인터를 안전하게 관리하는 방법을 학습합니다. C++의 고질적인 메모리 문제를 해결하는 Unreal의 자동 메모리 관리 시스템을 실습을 통해 체득합니다.

 

학습 목표

- Unreal Engine의 가비지 컬렉션 시스템 이해

- UObject 포인터의 안전한 관리 방법 학습

- 댕글링 포인터 문제 해결 방법 습득

- UPROPERTY의 중요성과 올바른 사용법 이해

- FGCObject를 사용한 고급 메모리 관리 기법 학습

 


 

C++ 메모리 관리의 고질적 문제

1. 메모리 누수

// ❌ 잘못된 예: 메모리 누수
void BadFunction()
{
    MyClass* Object = new MyClass();
    // delete를 호출하지 않음!
    // Object가 가리키는 메모리는 영원히 회수되지 않음
}

// ✅ 올바른 예: 수동 관리
void GoodFunction()
{
    MyClass* Object = new MyClass();
    // ... 사용 ...
    delete Object;  // 반드시 해제
    Object = nullptr;
}
 문제점
- new로 할당한 메모리를 delete로 해제하지 않음
- 힙 메모리가 계속 쌓여 시스템 메모리 고갈
- 게임이 길어질수록 성능 저하

 

2. 댕글링 포인터

// ❌ 위험한 상황
MyClass* Ptr1 = new MyClass();
MyClass* Ptr2 = Ptr1;  // 같은 객체를 가리킴

delete Ptr1;           // Ptr1으로 메모리 해제
Ptr1 = nullptr;

// Ptr2는 여전히 해제된 메모리를 가리킴!
Ptr2->DoSomething();   // 💥 크래시!
문제점
- 다른 곳에서 메모리를 해제함
- 포인터는 여전히 해제된 주소를 가리킴
- 접근 시 크래시 또는 예측 불가능한 동작

 

3. 와일드 포인터

// ❌ 초기화하지 않은 포인터
void DangerousFunction()
{
    MyClass* Ptr;  // 초기화 안 함! (쓰레기 값)
    
    if (SomeCondition)
    {
        Ptr = new MyClass();
    }
    
    // SomeCondition이 false면?
    Ptr->DoSomething();  // 💥 임의의 메모리 접근!
}

// ✅ 안전한 방법
void SafeFunction()
{
    MyClass* Ptr = nullptr;  // 반드시 초기화
    
    if (SomeCondition)
    {
        Ptr = new MyClass();
    }
    
    if (Ptr)  // nullptr 체크
    {
        Ptr->DoSomething();
    }
}
문제점
- 초기화하지 않은 포인터는 임의의 주소를 가리킴
- 운영체제 보호 영역 접근 시 크래시
- 디버그 어려움

 


 

가비지 컬렉션 시스템

개념

: 가비치 컬렉션(GC)은 프로그램에서 더 이상 사용하지 않는 객체를 자동으로 감지하여 메모리를 회수하는 시스템입니다.

 

도입 배경

- Java, C# 등 현대 언어들이 채택

- 메모리 안전성 향상

- 개발자 실수 방지

- 생산성 증대

 

Mark-and-Sweep 알고리즘

: Unreal Engine이 사용하는 가비지 컬렉션 방식입니다.

 

1단계 : Mark (표시)

Root Objects (시작점) :

- GameInstance

- World

- PlayerController

- 기타 RootSet 객체

 

2단계 : 참조 추적

모든 Root에서 참조로 도달 가능한 객체들에 Mark 플래그 설정

 

3단계 : Sweep (정리)

GUObjectArray 전체 스캔 :

- Mark가 되어 있지 않으면 가비지로 판정하여 메모리 회수

 


 

메모리 회수 방지 방법

1. UPROPERTY (가장 일반적)

UCLASS()
class UMyClass : public UObject
{
    GENERATED_BODY()
    
public:
    // ✅ UPROPERTY로 보호
    UPROPERTY()
    UTexture2D* Texture;
    
    // ✅ TObjectPtr 사용 (UE5)
    UPROPERTY()
    TObjectPtr<UTexture2D> TexturePtr;
    
    // ❌ UPROPERTY 없음 → GC에 수집됨!
    UTexture2D* UnprotectedTexture;
};

 

2. FGCObject 상속

UCLASS()
class UMyManager : public FGCObject
{
    GENERATED_BODY()
    
private:
    // UPROPERTY 사용 불가한 특수 상황
    TArray<UObject*> SpecialObjects;
    
public:
    // GC에 수동으로 참조 알림
    virtual void AddReferencedObjects(
        UObject* InThis, 
        FReferenceCollector& Collector
    ) override
    {
        Super::AddReferencedObjects(InThis, Collector);
        
        // 배열의 모든 객체를 참조로 등록
        Collector.AddReferencedObjects(SpecialObjects);
    }
    
    virtual FString GetReferencerName() const override
    {
        return TEXT("FMyManager");
    }
};
FGCObject 클래스를 상속 받아서 AddReferencedObjects, GetReferencerName을 구현하는 방법입니다.

 

3. RootSet 등록

void CreatePersistentObject()
{
    UMyObject* PersistentObject = NewObject<UMyObject>();
    
    // RootSet에 추가 → 절대 회수 안 됨
    PersistentObject->AddToRoot();
    
    // 나중에 제거 가능
    // PersistentObject->RemoveFromRoot();
}

 


 

UObject 유효성 검사

UMyObject* MyObject = /* ... */;

// 1. IsValid (일반적 사용)
if (IsValid(MyObject))
{
    MyObject->DoSomething();
}

// 2. IsValidLowLevel (저수준 검사) PendingKill 검사는 하지 않음
if (MyObject && MyObject->IsValidLowLevel())
{
    MyObject->DoSomething();
}

// 3. nullptr 체크만 (불충분!)
if (MyObject != nullptr)  // ⚠️ 댕글링 포인터 감지 못 함!
{
    MyObject->DoSomething();
}

'기타 > [강의] 이득우의 언리얼 프로그래밍 Part1' 카테고리의 다른 글

[이득우의 언리얼] 11. 언리얼 컨테이너 라이브러리 - 구조체, Map  (0) 2026.02.08
[이득우의 언리얼] 10. 언리얼 컨테이너 라이브러리 - TArray, TSet  (0) 2026.02.07
[이득우의 언리얼] 9. 언리얼 C++ 설계 - 델리게이트  (0) 2026.02.06
[이득우의 언리얼] 8. 언리얼의 C++ 설계 - 컴포지션  (0) 2026.02.06
[이득우의 언리얼] 7. 언리얼 C++ 설계 - 인터페이스  (0) 2026.02.04
'기타/[강의] 이득우의 언리얼 프로그래밍 Part1' 카테고리의 다른 글
  • [이득우의 언리얼] 11. 언리얼 컨테이너 라이브러리 - 구조체, Map
  • [이득우의 언리얼] 10. 언리얼 컨테이너 라이브러리 - TArray, TSet
  • [이득우의 언리얼] 9. 언리얼 C++ 설계 - 델리게이트
  • [이득우의 언리얼] 8. 언리얼의 C++ 설계 - 컴포지션
Meoyoung's Development Logs
Meoyoung's Development Logs
내가 보려고 만든 블로그
  • Meoyoung's Development Logs
    이게뭐영
    Meoyoung's Development Logs
  • 전체
    오늘
    어제
    • 분류 전체보기 (229)
      • 게임잼 (3)
      • 언리얼 엔진 (53)
        • 꿀 Tip ! (7)
        • 트러블슈팅 (24)
        • 최적화 (0)
        • 캐릭터 (2)
        • VR (1)
        • Lighting (2)
        • 멀티스레드 (2)
        • 문자열 (0)
      • C++ (31)
        • 문법 정리 (8)
        • [서적] Fundamental C++ 프로그래밍 .. (5)
        • [서적] 이것이 C++이다 (11)
        • [서적] Effective C++ (7)
      • C# (1)
        • [서적] 이것이 C#이다 (1)
      • 코딩테스트 (26)
        • 프로그래머스 (6)
        • 알고리듬 (13)
        • 자료구조 (7)
      • 컴퓨터 과학 (27)
        • 운영체제 (11)
        • 데이터베이스 (0)
        • 디자인패턴 (0)
        • 자료구조 (5)
        • 네트워크 (0)
        • 컴퓨터구조 (11)
      • 면접준비 (0)
        • C++ (0)
        • 운영체제 (0)
        • 자료구조 (0)
      • 프로젝트 (25)
        • [팀프로젝트] The Fourth Descenda.. (5)
        • [개인프로젝트] FPS 구현 맛보기 (5)
        • GetOutOf (15)
      • 기타 (54)
        • [강의] 이득우의 언리얼 프로그래밍 Part1 (10)
        • [강의] 이득우의 언리얼 프로그래밍 Part3 (12)
        • [강의] 소울라이크 개발 A-Z (4)
        • [강의] Udemy-2D (5)
        • [서적] 인생 언리얼5 (4)
        • 스파르타코딩클럽 (15)
        • 객체지향프로그래밍 (2)
        • 컴퓨터회로 (2)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    경북게임잼
    셸정렬
    삽입정렬
    게임개발
    선택정렬
    쉘정렬
    참가후기
    자료구조
    버블정렬
    알고리즘
    게임잼
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
Meoyoung's Development Logs
[이득우의 언리얼] 12. 언리얼 엔진의 메모리 관리
상단으로

티스토리툴바