본문으로 바로가기

[Unreal Engine 5] 메모리 관리

category UnrealEngine/Impl 2023. 6. 29. 12:19

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

그러다보니 프로그래머가 직접 할당 (new)과 해지 (delete) 짝 맞추기를 해야한다.

이를 잘 지키지 못하는 경우 다양한 문제가 발생할 수 있다.

잘못된 포인터를 사용하는 문제에는 다음과 같은것이 있다.

  • 메모리 누수 ( Leak ) : new를 했는데, delete 짝을 맞추지 못함. 힙에 메모리가 그대로 남아있음
  • 허상 ( Dangling ) 포인터 : (다른곳에서) 이미 해제해 무효화된 오브젝트의 주소를 가리키는 포인터
  • 와일드 ( Wild ) 포인터 : 값이 초기화되지 않아 엉뚱한 주소를 가리키는 포인터

C++ 이후에 나온 언어 Java / C# 은 이런 고질적인 문제를 해결하기 위해 포인터를 버리고 대신 가비지 컬렉션 시스템을 도입했다.

 

 

 

가비지 컬렉션 시스템

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

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

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

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

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

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

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

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

 

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

마크-스윕 방식의 가비지컬렉션 시스템을 자체적으로 구축함

지정된 주기마다 몰아서 없애도록 설정되어 있음(기본값 60 초)

성능 향상을 위해 병렬 처리, 클러스터링 같은 기능을 탑재함

 

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

GUObjectArray의 각 요소에는 플래그가 설정되어 있음

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

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

 

가비지 컬렉터는 GUObjectArray에 있는 플래그를 확인해 빠르게 회수해야 할 오브젝트를 파악하고 메모리에서 제거함

Garbage 플래그는 수동으로 설정하는 것이 아닌, 시스템이 알아서 설정함

한 번 생성된 언리얼 오브젝트는 즉시 삭제가 불가능함 GC에서 삭제가 될 때까지 기다려야 함 

 

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

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

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

콘텐츠 관련 오브젝트에 루트셋을 설정하는 방법은 권장되진 않음

 

언리얼은 다음과 같은 오브젝트를 회수 하지 않는다.

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

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

3. RootSet으로 지정된 언리얼 오브젝트

 

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

FGCObject를 상속받은 후 AddReferencedObjects 함수를 구현하면 된다

 

'UnrealEngine > Impl' 카테고리의 다른 글

Unreal Engine Class Default Object (CDO)  (0) 2023.09.16
Unreal Header Tool (UHT)  (0) 2023.09.16
Unreal Build Tool (UBT)  (2) 2023.09.16
언리얼 에디터를 빌드하기  (0) 2023.09.16
[Unreal Engine 5] 기본타입과 문자열  (0) 2023.06.22