inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

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

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

해결된 질문

469

상병

작성한 질문수 21

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의 기준이 달라서 그런것인지 궁금합니다.

unreal-engine 언리얼-c++

답변 1

0

이득우

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

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

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

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

0

상병

답변 감사드립니다.

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

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

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

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

0

이득우

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

1

상병

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

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

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

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

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

1

이득우

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

저는 저 노란색 미리보기 창이 안뜹니다

0

21

1

강의중에 사용하는 ppt 수업 자료

0

37

1

GetName(), SetName() 함수의 오버로딩 관련 문제 문의드립니다.

0

40

1

언리얼 공부 방법에 대해서 질문드립니다.

0

74

1

컴포지션을 위한 컴포넌트 생성에 관해 질문드립니다.

0

84

2

if (NameProp) 은 if (NameProp != nullptr)이랑 같은 의미인가요?

0

96

2

언리얼 계정 로그인 불가 문제

0

119

2

가비지컬렉션 주기를 짧게 유지하면 어떤 이슈가있을까요?

0

75

2

11강 TArray TSet 에 대해서 질문있습니다.

0

72

1

Unreal 연동 후 Visual Studio 빌드오류 제발 살려주십쇼

0

367

3

언리얼에서 제공하는 스마트 포인터 라이브러리 사용

0

75

2

FGCObject 상속 받은 객체에서 Uobject 삭제를 원할 때

0

80

2

게임 내 인벤토리 데이터를 관리 할 경우, TArray / TSet 무엇이 올바를까요?

0

75

2

8강 컴포지션 중 궁금한 것이 있습니다.

0

56

2

헤더 파일 분리 방법

0

85

2

언리얼 엔진 깃 설치

0

89

2

FObjectInitializer 를 사용한 생성자.

0

96

2

언리얼엔진 에서 새로운 클래스를 생성하면

0

75

2

GetName이 이미있는데용?

0

113

2

TObjectPtr 과 일반 포인터에 대한 용도 질문

0

105

2

UPROPERTY() 다음 라인에서 세미콜론이 입력되지 않습니다.

0

164

1

[18:50] 패키지 저장 시 이미 패키지가 있으면 로딩을 다 하고 저장하는 것이 좋은 이유가 궁금합니다

0

140

2

NonPropStudent가 GC이후 invalid된 이유

0

78

2

[44:22] 커스텀 구조체에서 GetTypeHash() 와 operator== 를 오버로딩 하는 이유에 대한 질문

0

108

2