본문 바로가기
Unreal

Unreal 메모리 관리

by myroad 2023. 8. 17.

Unreal의 참조 카운팅 시스템 - UObject클래스로부터 파생된 클래스 객체들의 메모리을 관리하는 시스템
UObject로 부터 파생되지 않는 클래스의 경우(순수 C++클래스의 경우) - TsharePtr, TWeakPtr를 사용해야 한다.



메모리 할당(객체 생성)
Unreal에서 더 이상 참조하지 않는 메모리 포인터는 즉시 지워지거나 마킹이 되어 다음 차례의 가비리 컬렉션때 삭제된다.
Unreal에서 메모리가 관리되기 위해서는 NewObject<> 또는 SpawnActor<>을 통해 객체가 생성되어야 한다.

UObject 파생 클래스는 NewObject<>을 통해 객체가 생성된다.
AActor 파생 클래스는 SpawnActor<>을 통해 객체가 생성된다.

Unreal에서 객체들의 포함관계
Package -> World -> Level -> UObject
Package은 World을 갖고 World은 Level을 작고 Level은 UObject을 가진다.
따라서 Package가 Unreal에서는 최 상위 저장소라고 보며 된다.

ConstructObject<>( )함수도 객체을 생성하는 함수로 NewObject<>( )와 비슷한 함수로 파라미터을 좀 더 구체적으로 설정할 수 있는 함수이다.
하지만 대부분 NewObject<>( )로 충분하다.



메모리 해제(객체 파괴)
UObject 인스턴스는 참조 카운터가 0이 되면 가비지 컬렉션 대상이 된다.
만약 참조 카운터가 0이 되기전에 해당 객체을 삭제하고 싶다면 UObject::ConditionalBeginDestroy()함수을 호출해 주면 수동으로 메모리를 해제할 수 있다.
UObject* object { NewObject<UObject>( ... ) };
object->ConditionalBeginDestroy();

따라서 ConditionalBeginDestroy()호출하게 되면 오버라이드 가능한 BeginDestroy와 FinishDestroy 함수가 호출된다.
하지만 주의할 것은 참조 카운터가 0이 되지 않은 상태에서 ConditionalBeginDestroy()을 호출하면 다른 객체가 해당 객체을 참조하고 있는 상황이므로 문제가 발생할 수 있다. 따라서 ConditionalBeginDestroy()을 호출할려면 먼저 참조 카운터가 0임을 확인하고 호출해 주어야 한다.



메모리 추적을 위한 스마트 포인터 사용
C++에 표준 스마트 포인터가 존재하는 것처럼 Unreal에도 스마트 포인터가 존재한다.
Unreal에서는 TSharePtr을 사용한다.
하지만 UObject파생 클래스 객체들은 이미 자체적인 참조 카운트 방식을 사용하므로 TSharePtr을 사용할 수 없다.

만약 당신이 UObject파생 클래스 객체가 아닌 순수 C++클래스 객체의 메모리을 관리하고 싶다면 TSharedPtr와 TSharedRef은 좋은 선택이다.
(new키워드을 통한 메모리 할당 객체인 경우~)

- TSharedPtr : 스레드로부터 안전한 (ESPMode::ThreadSafe를 인자로 넘긴다면) 참조 카운트 포인터 타입으로, 공유 객체를 나타낸다. 참조 카운트가 없을 때 할당 해제 된다.


- TSharedRef : null이 불가능한 TSharedPtr이다. TSharedPtr로 변환이 가능하다.


- TScopedPointer : { } 블록에서 블록의 끝에서 자동으로 삭제되는 포인터

{
    TScopedPointer<AActor> warrior(this);
} // 이곳에서 삭제됨


일반 C++ 클래스을 new로 메모리 할당하고 TSharedPtr로 감싸주는 방법

//C++ 표준 클래스의 메모리 할당 및 스마트 포인터 사용

class MyClass {};
TSharedPtr<MyClass> sharedPtr { new MyClass() };

TSharedPtr<MyClass> ptr { sharedPtr };


TArray은 UPROPERTY을 사용해야 메모리가 관리된다.

 

가비지 켈렉션 강제로 수행하는 방법

GetWorld()->ForceGarbageCollection(true);

 

참고 - https://openmynotepad.tistory.com/89