ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 언리얼의 가비지 컬렉터(GC)
    게임 상용엔진/Unreal 2025. 2. 19. 19:13

    언리얼 엔진의 자동 메모리 관리

    C++은 저수준으로 메모리 주소에 직접 접근하는 포인터를 사용해 오브젝트를 관리한다

    따라서 직접 할당과 해지 짝 맞추기를 진행해주어야 한다 (new, delete)

     

    잘못된 포인터의 사용 예시로

     - 메모리 누수 (Leak) : new를 했는데 delete 짝을 맞추지 못하였을 때, 힙에 메모리가 그대로 남아있게 된다

     - 허상 포인터 (dangling) : 이미 해제해 무효화된 오브젝트의 주소를 가리키는 포인터

     - 와일드 포인터 (Wild) : 값이 초기화되지 않아 엉뚱한 주소를 가리키는 포인터

    잘못된 포인터 값은 다양한 문제를 일으킬 수 있으며 한 번의 실수로 프로그램을 종료시킬 가능성이 존재한다

     

    언리얼의 가비지 컬렉션 시스템

    프로그램에서 더 이상 사용하지 않는 오브젝트를 자동으로 감지해 메모리를 회수하는 시스템이다

    동적으로 생성된 모든 오브젝트 정보를 모아둔 저장소를 사용해 사용되지 않는 메모리를 추적한다

    마크 스윕 방식의 가비지 컬렉션 (Mark - Sweep)

     1. 저장소에서 최초 검색을 시작하는 루트 오브젝트를 표기한다.

     2. 루트 오브젝트가 참조하는 객체를 찾아 마크한다.

     3. 마크된 객체로부터 다시 참조하는 객체를 찾아 마크하고 이를 계속 반복한다.

     4. 이제 저장소에는 마크된 객체와 마크되지 않은 객체의 두 그룹으로 나뉜다.

     5. 가비지 컬렉터가 저장소에서 마크되지 않은 객체(가비지)들의 메모리를 회수한다. (Sweep)

     

    가비지 컬렉션을 위한 객체 저장소

    관리되는 모든 언리얼 오브젝트의 정보를 저장하는 전역 변수 GUObjectArray가 있다

    위의 GUObjectArray의 각 요소에는 플래그(Flag)가 설정되어 있다

     - Garbage 플래그 : 다른 언리얼 오브젝트로부터의 참조가 없어 회수 예정인 오브젝트

     - RootSet 플래그 : 다른 언리얼 오브젝트로부터 참조가 없어도 회수하지 않는 특별한 오브젝트

    가비지 컬렉터는 지정된 시간에 따라 주기적으로 메모리를 회수한다

    Garbage 플래그로 설정된 오브젝트를 파악하고 메모리를 안전하게 회수하되, 이 플래그는 수동으로 설정하는 것이 아닌 시스템이 알아서 설정한다

    ! 한번 생성된 언리얼 오브젝트는 바로 삭제가 불가능하다

     

    루트셋 플래그의 설정

    AddToRoot 함수를 호출해 루트셋 플래그를 설정하면 최초 탐색 목록으로 설정된다

    루트셋으로 설정된 언리얼 오브젝트는 메모리 회수로부터 보호받는다

    RemoveFromRoot 함수를 호출해 루트셋 플래그를 제거할 수 있다

    ! 컨텐츠 관련된 오브젝트에 루트셋을 설정하는 방법은 추천하지 않는다

     

    언리얼 오브젝트를 통한 포인터 문제의 해결

    메모리 누수 문제

     - 언리얼 오브젝트는 가비지 컬렉터를 통해 자동으로 해결한다

     - C++ 오브젝트는 직접 신경써야 한다 (스마트 포인터 라이브러리의 활용)

    댕글링 포인터 문제

     - 언리얼 오브젝트는 이를 탐지하기 위한 함수를 제공한다 (::IsValid())

     - C++ 오브젝트는 직접 신경써야 한다 (스마트 포인터 라이브러리의 활용)

    와일드 포인터 문제

     - 언리얼 오브젝트에 UPROPERTY 속성을 지정하면 자동으로 nullptr로 초기화 해준다

     - C++ 오브젝트의 포인터는 직접 nullptr로 초기화 해야한다 (또는 스마트 포인터 라이브러리의 활용)

     

    회수되지 않는 언리얼 오브젝트

    언리얼 엔진 방식으로 참조를 설정한 언리얼 오브젝트

     - UPROPERTY로 참조된 언리얼 오브젝트

     - AddReferencedObject 함수를 통해 참조를 설정한 언리얼 오브젝트

    루트셋(RootSet)으로 지정된 언리얼 오브젝트

    ! 오브젝트 포인터는 가급적 UPROPERTY로 선언하고, 메모리는 가비지 컬렉터가 자동으로 관리하도록 위임한다

     

    ※ 일반 클래스에서 언리얼 오브젝트를 관리하는 경우

    UPROPERTY를 사용하지 못하는 일반 C++클래스가 언리얼 오브젝트를 관리해야 하는 경우

    FGCObject 클래스를 상속받은 후 AddReferencedObjects 함수를 구현한다

    함수 구현 부에서 관리할 언리얼 오브젝트를 추가해준다

     

    언리얼 오브젝트의 관리 원칙

    생성된 언리얼 오브젝트를 유지하기 위해 레퍼런스 참조 방법을 설계하는 것이다

     - 언리얼 오브젝트 내의 언리얼 오브젝트 : UPROPERTY 사용

     - 일반 C++ 오브젝트 내의 언리얼 오브젝트 : FGCOBject의 상속 후 구현

    생성된 언리얼 오브젝트는 강제로 지우려 하지 않는 것이다

     - 참조를 끊는다는 생각으로 설계하는 것

     - 가비지 컬렉터에게 회수를 재촉할 수는 있음 (ForceGarbageCollection 함수)

     - 컨텐츠 제작에서 Destroy함수를 사용할 수 있으나, 결국 내부 동작은 동일 (가비지 컬렉터에 위임)

     

     

     

     

     

     

     

     

     

     

    언리얼 C++ Part 1. 노트정리!

     

    1단계_12. 언리얼 엔진의 메모리 관리 | Notion

    강의의 주요적인 목표

    ideugu.notion.site

     

    '게임 상용엔진 > Unreal' 카테고리의 다른 글

    [UE5] BPClass에서 StaticMesh로 변환  (0) 2024.12.11
    언리얼의 자잘한 팁  (0) 2020.07.12

    댓글