언리얼은 구조 설계에서 Garbage Collector (이하 GC)를 제공한다.
하지만, GC를 제공하는 어떤 언어에서나 통용되지만, GC가 사용되는 상황을 잘 이해하고 써야, 메모리 누수(Memory Leak)이 발생하지 않는다.
언리얼에서의 GC의 특징은 다음과 같다.
Unreal Garbage Collector
- Class의 소멸 시기와 같은 UObject를 상속하는 멤버 변수들은 UPROPERTY 매크로로 선언
- Class 내에 포인터 멤버 변수는 UObject를 상속 하는 멤버 변수들로 한정
- UStruct는 GC에 해당되지 않음
- GC의 사용이 원치 않는 Class의 경우, 아래의 함수를 사용하여 GC의 대상에서 제외
- UObjectBaseUtility::AddToRoot()
- UObjectBaseUtility::SetFlags()
GC는 언제 실행될지 모르기 때문에, 관리를 잘 해주어야 한다.
Blueprint의 사용을 원치 않더라도, 항상 UObject의 변수들은 UPROPERTY 매크로의 사용을 추천한다.
UPROPERTY 매크로는 GC 뿐만이 아니라 언리얼 GameSave에도 해당하기 때문에, 가능한 매크로를 사용하는 것이 좋다.
함수가 필요없고, 데이터 만을 사용하는 변수들은 Class가 아닌 Struct의 사용을 추천한다.
Struct는 기본적으로 GC에 해당하지 않고, Class 내에 멤버 변수로써 사용하게 되면, 스택 메모리로 사용하게 되어 Class의 소멸과 함께 소멸되기 때문이다.
GC의 관리를 잘못하게 되면, 디버그 도중일 경우 아래와 같은 에러가 뜨게 된다.
디버그 도중이 아니라면 Crash창으로 뜨기 때문에 가능하면 디버그 상태로 Unreal을 사용하는 것을 추천한다.
위의 사진과 같이 'read access violation' 예외는 메모리에서 삭제된 포인터를 참조하는 에러이다.
에러의 해결 방법은 GC의 대상에서 제외하여, 직접 삭제해주는 방법이 있다.
이 방법은 개인적인 해결방법이었으므로, 더 좋은 해결방법이 있으면 언제든지 말씀해주시면 참고하여 수정하겠습니다.
에러가 사용되는 멤버 변수 클래스로 이동하여, 생성자에서 GC의 수집 대상에서 제외해주는 코드를 작성한다.
UObjectBaseUtility::AddToRoot or UObjectBaseUtility::SetFlags(EObjectFlag::RF_MarkAsRootSet)
위의 코드를 사용하면, 수집 대상에서 제외되기 때문에 메모리의 소멸이 일어나지 않는다.
때문에 메모리의 원하는 소멸 시점에 아래의 코드를 작성한다.
if (!ptr) return ;
if (!ptr->IsValidLowLevel()) return ;
ptr->ConditionalBeginDestroy();
ptr = nullptr;
ptr이 없거나, IsValidLowLevel 함수를 통하여 유효성 검사를 한다.
객체가 존재하면서, 유효성이 있다면 ConditionalBeginDestory 함수를 통하여 GC의 수집 대상에 포함시킨다.
GC의 수집 대상에 포함이 아니라, GC에 추가를 원한다면 World::ForceGarbageCollection(bool bFullPurge) 함수를 사용하면 된다.
강조하여, GC는 컴파일러 마다 GC Size에 가득차게 되거나, Scene 전환과 같은 모든 오브젝트를 삭제해야 되는 시점에 호출이 된다.
때문에 프로그래머가 원치 않는 시점에 GC가 실행되어, 프로그램의 실행이 생각과는 다르게 되는 경우가 있기 때문에, GC의 사용법과 관리가 중요하다.
'게임 개발 끄적 > Unreal (C++)' 카테고리의 다른 글
[UE4] Unreal C++ 한글 출력 에러 (1) | 2018.11.07 |
---|---|
[UE4] Thread (0) | 2018.06.21 |
[UE4] Voice Capture (0) | 2018.03.20 |
[UE4] Render Capture Scene (0) | 2018.03.19 |
[UE4] File Copy & Explorer (0) | 2018.03.19 |