인프런 커뮤니티 질문&답변

상병님의 프로필 이미지

작성한 질문수

이득우의 언리얼 프로그래밍 Part1 - 언리얼 C++의 이해

언리얼 엔진에서 순환 참조가 발생할 수 있나요? + TWeakObjectPtr

해결된 질문

24.06.15 18:01 작성

·

208

·

수정됨

0

안녕하세요, 교수님. 문득 궁금한게 생겨 다시 강의를 보다가 질문을 올립니다.

우선 순환참조는 스마트 포인터의 고질적인 문제인데요,

A, B, C가 있고,

A -> B <->C 의 참조 상태에서 A 변수의 참조가 끊겨도, B와 C는 서로 계속 가리키고 있어 영원히 메모리가 해제되지 않는 메모리 누수의 문제로 알고 있습니다. 따라서 weak_ptr<T>를 사용해야 하는데요.

 

UE의 GC 시스템은 Mark & Sweep 방식을 따른다고 했습니다.

전체 UObject에 대해 Unreachable로 설정 후,

Rootset을 따라서 참조 그래프를 순회하며 Unreachable 플래그를 해제하고 (Mark),

전체 UObject에 대해 Unreachable 플래그가 존재하면 메모리 해제를 진행한다. (Sweep)

 

이 방식은 Java나 c#의 GC와 비슷한 방식이며, 해당 언어의 경우

순환 참조 문제가 발생하지 않는 것으로 알고 있습니다.

(위에 써둔 순환 참조 문제에서, B<->C의 참조 상태여도 어차피 Root로 부터 Mark가 도달할 수 없기 때문에 지워짐)

 

그렇다면 언리얼 엔진의 GC에서도 위와 같은 순환 참조 문제가 발생하지 않나요?

발생하지 않는다면, TWeakObjectPtr<T>의 강참조 방지는 그냥 쓸데없는 생명주기 연장 + raw pointer 참조 시 GC 당해서 댕글링을 참조하는 문제 방지 등을 위해서 사용하는 것인가요?

 

만약 발생한다면, 그 이유는 무엇인가요? 제가 잘못 이해한건지, 아니면 Java나 C#에서의 RootSet 기준과 Unreal 에서의 Rootset의 기준이 달라서 그런것인지 궁금합니다.

답변 1

0

이득우님의 프로필 이미지
이득우
지식공유자

2024. 06. 16. 22:25

Java와 C#이라고 상호참조 문제가 발생하지 않는 것은 아닙니다.
C++과는 조금 다른 유형이지만, 불필요하게 한 인스턴스가 특정 객체를 계속 레퍼런싱하는 경우 GC에 탐지되지 않기 때문에 메모리에서 내려오지 않는 문제가 발생합니다. 이를 방지하기 위해 서로 참조해야하는 상황이 발생할 때는 한 곳은 레퍼런싱 카운팅 없는 약참조를 걸도록 설계해야 해당 객체가 모두 사용될 때 비로소 메모리가 해지됩니다.
예를 들어 UI매니저 같이 객체에 대한 소유권이 없고, 게임 중에 계속 살아있는 클래스는 가급적 약참조를 걸고 있는게 바람직합니다.

언리얼은 Native C++과 Java/C#의 두 가지를 모두 사용하므로, 두 개의 약참조 API를 제공합니다.

  • Native C++ 용 스마터포인터 약참조 클래스 : TWeakPtr<T>

  • 언리얼 오브젝트용 약참조 클래스 : TWeakObjectPtr<T>

상병님의 프로필 이미지
상병
질문자

2024. 06. 17. 01:46

답변 감사드립니다.

그렇다면, 언리얼 GC의 관리를 받는 UObject의 경우 예를 들어서

B<->C 서로를 강참조로 가리켜서 메모리에 올라가 있지만,

그 외에는 아무도 B나 C를 참조 하지 않고, '현재 프로그램 내에 B와 C에 접근할 수 있는 포인터 변수'도 없어져 메모리 누수의 위험이 발생 하였다면,

해당 경우에서는 Mark가 닿지 못하여 GC에 의해 해제 되는것이 맞나요?

이득우님의 프로필 이미지
이득우
지식공유자

2024. 06. 17. 10:23

음.. 그 부분까지 답변 드리려면 실험을 해봐야 할 것 같은데,
우선 엔진에서 언리얼 오브젝트를 쓰면서, 접근할 수단을 잃어버려 고아가 되는 상황이 발생할까 싶습니다. 콘텐츠를 구성하는 언리얼 오브젝트는 레벨이나 싱글톤 매니저로부터 철저하게 관리되고 있어서요. 의도적이지 않은 상황에서 어떤 경우가 있을까요?

상병님의 프로필 이미지
상병
질문자

2024. 06. 17. 13:16

일반적인 상황이 아니긴 하지만,

일반 shared_ptr<> 과 TSharedPtr<> 같이 스마트 포인터를 사용할 시에 발생할 수 있는 '고아로 인한 누수 상태'가

언리얼 GC에 의해 관리되는 메모리에서도 발생할 수 있는지, 발생된다면 처리가 어떻게 되는지 궁금한 것이었습니다.

말씀을 들어보니 발생시키기도 어려울 것 같다는 생각이 듭니다.

한번 가능할 것 같은 상황이 생기면 실험해보겠습니다. 감사합니다.

이득우님의 프로필 이미지
이득우
지식공유자

2024. 06. 17. 15:39

네 제안해주신 질문은 아주 좋은 주제입니다.
한번 엔진 소스 코드를 보면서 연구해 정리하면 좋은 포트폴리오가 될 것으로 생각합니다 ^^

상병님의 프로필 이미지

작성한 질문수

질문하기