728x90
반응형
- 정리
- 언리얼 메모리 관리 시스템
- C++ 언어의 고질적인 문제인 포인터 문제의 이해
- 이를 해결하기 위한 가비지 콜렉션의 동작 원리의 이해와 설정 방법
- 다양한 상황에서 언리얼 오브젝트를 생성하고 메모리에 유지하는 방법의 이해
- 언리얼 오브젝트 포인터를 선언하는 코딩 규칙의 이해
- 언리얼 메모리 관리 시스템
- C++ 언어 메모리 관리의 문제점
- C++은 저수준으로 메모리 주소에 직접 접근하는 포인터를 사용해 오브젝트를 관리한다.
- 그러다보니 직접 할당(new)과 해지(delete) 짝 맞추기를 해야 한다.
- 잘못된 포인터 사용 예시
- 메모리 누수
- 허상 포인터
- 와일드 포인터
- 잘못된 포인터 값은 다양한 문제를 일으키며, 한번의 실수는 프로그램을 종료시킴
- C++ 이후에 나온 언어 Java/C#은 이런 고질적인 문제를 해결하기 위해 포인터를 버리고 대신 가비지 컬렉션 시스템을 도입함
- 가비지 컬렉션 시스템
- 프로그램에서 더 이상 사용하지 않는 오브젝트를 자동으로 감지해 메모리를 회수하는 시스템
- 동적으로 생성된 모든 오브젝트 정보를 모아둔 저장소를 사용해 사용되지 않는 메모리를 추적
- 언리얼 엔진의 가비지 컬렉션 시스템
- 지정된 주기마다 몰아서 없애도록 설정되어 있음. (GCCycle. 기본 값 60초)
- 성능 향상을 위해 병렬 처리, 클러스터링과 같은 기능을 탑재함
- 가비지 컬렉션을 위한 객체 저장소
- 관리되는 모든 언리얼 오브젝트의 정보를 저장하는 전역 변수 : GUObjectArray
- GUObjectArray 의 각 요소에는 플래그(Flag)가 설정되어 있음
- 가비지 컬렉터가 참고하는 주요 플래그
- Garbage 플래그
- 다른 언리얼 오브젝트로부터의 참조가 없어 회수 예정인 오브젝트
- RootSet 플래그
- 다른 언리얼 오브젝트로부터 참조가 없어도 회수하지 않는 특별한 오브젝트
- Garbage 플래그
- 가비지 컬렉터의 메모리 회수
- 가비지 컬렉터는 지정된 시간에 주기적으로 메모리를 회수한다.
- Garbage 플래그로 설정된 오브젝트를 파악하고 메모리를 안전하게 회수함
- Garbage 플래그는 수동으로 설정하는 것이 아닌, 시스템이 알아서 설정함
- 한 번 생성된 언리얼 오브젝트는 바로 삭제가 불가능함
- 루트셋 플래그의 설정
- AddToRoot 함수를 호출해 루트셋 플래그를 설정하면 최초 탐색 목록으로 설정됨
- 루트셋으로 설정된 언리얼 오브젝트는 메모리 회수로부터 보호받음
- RemoveFromRoot 함수를 호출해 루트셋 플래그를 제거할 수 있음
- 콘텐츠 관련 오브젝트에 루트셋을 설정하는 방법은 권장되진 않음
- 언리얼 오브젝트를 통한 포인터 문제의 해결
- 메모리 누수 문제
- 언리얼 오브젝트는 가비지 컬렉터를 통해 자동으로 해결
- C++ 오브젝트는 직접 신경써야 함
- 댕글링 포인터 문제
- 언리얼 오브젝트는 이를 탐지하기 위한 함수를 제공함 ::IsValid()
- C++ 오브젝트는 직접 신경써야 함
- 와일드 포인터 문제
- 언리얼 오브젝트에 UPROPERTY 속성을 지정하면 자동으로 nullptr로 초기화 해줌
- C++ 오브젝트의 포인터는 직접 nullptr로 초기화 할 것
- 메모리 누수 문제
- 프로그래머들이 많이 실수하는 부분이기 때문에 잘 파악해서 언리얼 오브젝트와 C++ 오브젝트의 메모리 관리를 각각 따로따로 신경을 써줘야 한다.
- 회수되지 않는 언리얼 오브젝트
- 언리얼 엔진 방식으로 참조를 설정한 언리얼 오브젝트
- UPROPERTY로 참조된 언리얼 오브젝트 (대부분의 경우 이를 사용)
- AddReferencedObject 함수를 통해 참조를 설정한 언리얼 오브젝트
- 루트셋(RootSet)으로 지정된 언리얼 오브젝트
- 언리얼 엔진 방식으로 참조를 설정한 언리얼 오브젝트
(오브젝트 선언의 기본 원칙) 오브젝트 포인터는 가급적 UPROPERTY로 선언하고, 메모리는 가비지컬렉터가 자동으로 관리하도록 위임한다.
- 일반 클래스에서 언리얼 오브젝트를 관리하는 경우
- UPROPERTY를 사용하지 못하는 일반 C++ 클래스가 언리얼 오브젝트를 관리해야 하는 경우
- FGCObject클래스를 상속받은 후 AddReferencedObjects 함수를 구현한다.
- 함수 구현 부에서 관리할 언리얼 오브젝트를 추가해 줌
- 언리얼 오브젝트의 관리 원칙
- 생성된 언리얼 오브젝트를 유지하기 위해 레퍼런스 참조 방법을 설계할 것
- 언리얼 오브젝트 내의 언리얼 오브젝트
- UPROPERTY사용
- 일반 C++ 오브젝트 내의 언리얼 오브젝트
- FGCObject의 상속 후 구현
- 언리얼 오브젝트 내의 언리얼 오브젝트
- 생성된 언리얼 오브젝트는 강제로 지우려 하지 말 것
- 참조를 끊는다는 생각으로 설계할 것
- 가비지 컬렉터에게 회수를 재촉할 수는 있음 (ForceGarbageCollection 함수)
- 콘텐츠 제작에서 Destroy함수를 사용할 수 있으나, 결국 내부 동작은 동일함. (가비지 컬렉터에 위임)
- 생성된 언리얼 오브젝트를 유지하기 위해 레퍼런스 참조 방법을 설계할 것
TObjectPtr<class UStudent> NonPropStudent;
UPROPERTY()
TObjectPtr<class UStudent> PropStudent;
- MyGameInstance.h
void CheckUObjectIsValid(const UObject* InObject, const FString& InTag)
{
if (InObject->IsValidLowLevel())
{
UE_LOG(LogTemp, Log, TEXT("[%s] 유효한 언리얼 오브젝트"), *InTag);
}
else
{
UE_LOG(LogTemp, Log, TEXT("[%s] 유효하지 않은 언리얼 오브젝트"), *InTag);
}
}
void UMyGameInstance::Init()
{
Super::Init();
NonPropStudent = NewObject<UStudent>();
PropStudent = NewObject<UStudent>();
}
void UMyGameInstance::Shutdown()
{
Super::Shutdown();
CheckUObjectIsNull(NonPropStudent, TEXT("NonPropStudent"));
CheckUObjectIsValid(NonPropStudent, TEXT("NonPropStudent"));
CheckUObjectIsNull(PropStudent, TEXT("PropStudent"));
CheckUObjectIsValid(PropStudent, TEXT("PropStudent"));
}
- MyGameInstance.cpp
- 언리얼 오브젝트 선언에서 언리얼 오브젝트의 클래스 멤버 변수를 선언할때는 반드시 UPROPERTY()를 붙여줘야만 댕글링 포인터 문제에서 벗어날 수가 있다.
- 일반 C++클래스에서 언리얼 오브젝트를 관리할 때, FGCObject를 상속하고 해당 함수들을 구현해줘야 댕글링 포인터 문제가 발생하지 않는다.
- AddReferencedObject()
- GetReferencerName()
void FStudentManager::AddReferencedObjects(FReferenceCollector& Collector)
{
if (SafeStudent->IsValidLowLevel())
{
Collector.AddReferencedObject(SafeStudent);
}
}
- StudentManager.cpp
class UNREALMEMORY_API FStudentManager : public FGCObject
{
public:
FStudentManager(class UStudent* InStudent) : SafeStudent(InStudent) {}
virtual void AddReferencedObjects(FReferenceCollector& Collector) override;
virtual FString GetReferencerName() const override
{
return TEXT("FStudentManager");
}
const class UStudent* GetStudent() const { return SafeStudent; }
private:
class UStudent* SafeStudent = nullptr;
};
- StudentManager.h
해당 포스트는 인프런의 <이득우의 언리얼 프로그래밍 Part1 - 언리얼 C++의 이해>
강의를 수강하고 정리한 내용입니다.
이득우의 언리얼 프로그래밍 Part1 - 언리얼 C++의 이해 | 이득우 - 인프런
이득우 | 대기업 현업자들이 수강하는 언리얼 C++ 프로그래밍 전문 과정입니다. 언리얼 엔진 프로그래머라면 게임 개발전에 반드시 알아야 하는 언리얼 C++ 기초에 대해 알려드립니다., [사진] 언..............................
www.inflearn.com
728x90
'공부 > 이득우의 언리얼 프로그래밍' 카테고리의 다른 글
[Study] Part 1 - 언리얼 오브젝트 관리 II - 패키지 (14/15) (0) | 2024.05.09 |
---|---|
[Study] Part 1 - 언리얼 오브젝트 관리 I - 직렬화 (13/15) (0) | 2024.05.08 |
[Study] Part 1 - 언리얼 컨테이너 라이브러리 II - 구조체와 Map (11/15) (0) | 2024.05.03 |
[Study] Part 1 - 언리얼 컨테이너 라이브러리 I - Array와 Set (10/15) (0) | 2024.05.02 |
[Study] Part 1 - 언리얼 C++ 설계 Ⅲ - 델리게이트 (9/15) (0) | 2024.04.30 |