일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- CTF
- frequency-domain spectrum analysis
- sampling theory
- Unity #Indie Game
- pdlc
- Security
- stride
- MLFQ
- DSP
- dirty cow
- 유니티
- linear difference equation
- DP
- MAC
- 유스케이스
- 언리얼엔진
- TSet
- Double free
- ret2libc
- STCF
- Rr
- Race condition
- AINCAA
- 게임개발
- 메카님
- 운영체제
- dtft
- 배경 그림
- 게임 개발
- RBAC
- Today
- Total
다양한 기록
[UE] Memory Management 본문
기존 C++ : new, delete 해줘야 함
-> 누수, 댕글링 포인터, 초기화되지 않은 포인터 등
문제가 많이 발생함
가비지 컬렉션 시스템
- 프로그램에서 더 이상 사용하지 않는 오브젝트를 자동 감지하여 회수
- 동적으로 생성된 모든 오브젝트 정보를 모아둔 저장소를 사용해 사용되지 않는 메모리 추적
- 마크-스윕(Mark-Sweep) 방식의 가비지 컬렉션
- 저장소에서 최초 검색을 시작하는 루트 오브젝트 표기
- 루트 오브젝트가 참조하는 객체를 찾아 마크
- 마크된 객체에서 계속해서 참조하는 객체를 찾아 마크(1로 표시)
- 마크되지 않은 객체(0으로 표시) -> 회수(스윕)
언리얼 엔진에선 주기적으로 알아서 작동
기본 값 60초, 부하가 좀 있는 작업인데 병렬 처리 및 클러스터링 기능 탑재
가비지 컬렉터를 위한 객체 저장소
- 관리되는 모든 언리얼 오브젝트의 정보를 저장하는 전역 변수: GUObjectArray
- GUObjectArray의 각 요소는 플래그를 가짐
- Garbage 플래그: 참조가 없어 회수 예정
- RootSet 플래그: 참조가 없어도 회수하지 않는 오브젝트 (최초라 보면 됨)
메모리 회수
- 지정된 시간에 따라 메모리 회수
- 가비지 플래그로 설정된 오브젝트를 파악하고 메모리를 안전하게 회수
- 가비지 플래그는 시스템이 알아서 설정함
- 어떤 오브젝트가 너무 중요해서 사라지면 안된다 -> 루트셋으로 등록하면 됨
- AddToRoot 함수를 호출해 루트셋 플래그 설정 가능
- RemoveFromRoot 호출하여 루트셋 플래그 제거 가능
장점
- 메모리 누수 안됨 (알아서 해줌)
- 댕글링 포인터 (IsValid 같은 탐지용 함수를 제공함)
- 와일드 포인터 (UPROPERTY로 지정하면 자동 nullptr 초기화)
회수되지 않는 언리얼 오브젝트
- UPROPERTY로 참조된 언리얼 오브젝트
- AddReferencedObject 함수를 통해 참조를 설정한 언리얼 오브젝트
- 루트셋으로 지정된 언리얼 오브젝트 (많이 안 씀)
* C++ 객체 내에 언리얼 오브젝트가 멤버로 들어가면 두번째 방법을 써야 함
* 이때, 언리얼 오브젝트가 FGCObject를 상속받고 AddReferencedObject 구현해주면 됨
주의 사항
생성된 언리얼 오브젝트는 강제로 지우려 하지 말 것
- 참조를 끊는다는 생각
- 가비지 컬렉터에게 회수 재촉은 가능 (ForceGarbageCollection 함수)
- 콘텐츠 제작에서 Destroy 함수 사용도 가능한데 이것도 결국 가비지 컬렉터가 나중에 처리해야 함
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Engine/GameInstance.h"
#include "MyGameInstance.generated.h"
/**
*
*/
UCLASS()
class UNREALMEMORY_API UMyGameInstance : public UGameInstance
{
GENERATED_BODY()
public:
virtual void Init() override;
virtual void Shutdown() override;
private:
TObjectPtr<class UStudent> NonPropStudent;
UPROPERTY()
TObjectPtr<class UStudent> PropStudent;
TArray<TObjectPtr<class UStudent>> NonPropStudents;
UPROPERTY()
TArray<TObjectPtr<class UStudent>> PropStudents;
class FStudentManager* StudentManager = nullptr;
};
// Fill out your copyright notice in the Description page of Project Settings.
#include "MyGameInstance.h"
#include "Student.h"
#include "StudentManager.h"
void CheckUObjectIsValid(const UStudent* InObject, const FString& InTag)
{
if ( InObject->IsValidLowLevel() )
{
UE_LOG(LogTemp, Log, TEXT("[%s] 유효한 언리얼 오브젝트"), * InTag);
}
else
{
UE_LOG(LogTemp, Log, TEXT("[%s] 유효하지 않은 언리얼 오브젝트"), *InTag);
}
}
void CheckUObjectIsNull(const UStudent* InObject, const FString& InTag)
{
if (InObject == nullptr)
{
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>();
NonPropStudents.Add(NewObject<UStudent>());
PropStudents.Add(NewObject<UStudent>());
StudentManager = new FStudentManager( NewObject<UStudent>(), NewObject<UStudent>());
UE_LOG(LogTemp, Log, TEXT("===== Init ===="));
}
void UMyGameInstance::Shutdown()
{
Super::Shutdown();
const UStudent* SafeStudentInManager = StudentManager->GetSafeStudent();
const UStudent* UnSafeStudentInManager = StudentManager->GetUnSafeStudent();
delete StudentManager;
StudentManager = nullptr;
CheckUObjectIsValid(NonPropStudent, TEXT("NonPropStudent"));
CheckUObjectIsNull(NonPropStudent, TEXT("NonPropStudent"));
CheckUObjectIsValid(PropStudent, TEXT("PropStudent"));
CheckUObjectIsNull(PropStudent, TEXT("PropStudent"));
CheckUObjectIsValid(NonPropStudents[0], TEXT("NonPropStudents"));
CheckUObjectIsNull(NonPropStudents[0], TEXT("NonPropStudents"));
CheckUObjectIsValid(PropStudents[0], TEXT("PropStudents"));
CheckUObjectIsNull(PropStudents[0], TEXT("PropStudents"));
CheckUObjectIsValid(UnSafeStudentInManager, TEXT("UnSafeStudentInManager"));
CheckUObjectIsNull(UnSafeStudentInManager, TEXT("UnSafeStudentInManager"));
CheckUObjectIsValid(SafeStudentInManager, TEXT("SafeStudentInManager"));
CheckUObjectIsNull(SafeStudentInManager, TEXT("SafeStudentInManager"));
}
IsValidLowLevel은 객체의 메모리 구조가 유효한지를 체크
UPROPERTY로 지정된 객체는 회수가 안되고,
FGCObject를 구현하여 설정한 경우에도 회수가 안됨, 그걸 확인해보는 코드
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
/**
*
*/
class UNREALMEMORY_API FStudentManager : FGCObject
{
public:
FStudentManager(class UStudent* InSafeStudent, class UStudent* InUnSafeStudent) :
SafeStudent(InSafeStudent), UnSafeStudent(InUnSafeStudent) {}
const class UStudent* GetSafeStudent() const { return SafeStudent; }
const class UStudent* GetUnSafeStudent() const { return UnSafeStudent; }
// FGCObject 구현
virtual void AddReferencedObjects( FReferenceCollector& Collector ) override;
virtual FString GetReferencerName() const override
{
return TEXT("FStudentManager");
}
private:
class UStudent* SafeStudent = nullptr;
class UStudent* UnSafeStudent = nullptr;
};
// Fill out your copyright notice in the Description page of Project Settings.
#include "StudentManager.h"
#include "Student.h"
void FStudentManager::AddReferencedObjects(FReferenceCollector& Collector)
{
if ( SafeStudent->IsValidLowLevel() )
{
Collector.AddReferencedObject(SafeStudent);
}
}
FGCObject의 경우 SafeStudent는 AddReferencedObject에서 설정해주고, UnSafeStudent는 설정 안함
GetReferencerName은 클래스 이름 넣어주면 됨
가비지 콜렉터 동작 전에 애플리케이션을 꺼버리면 전부 멀쩡히 나옴
가비지 컬렉터가 동작한 후에는,
UPROPERTY가 설정된 것들의 경우엔 GC에 의해 회수당하지 않았고,
추가적으로 FGCObject 상속받아 구현까지 한 것은 회수당하지 않았음
나머지는 회수당함
'언리얼 엔진 > Unreal C++' 카테고리의 다른 글
[UE] Package (0) | 2025.01.01 |
---|---|
[UE] Serialization (직렬화) (0) | 2024.12.30 |
[UE] Unreal Container Library / Struct, Map (0) | 2024.12.28 |
[UE] Unreal Container Library / TArray, TSet (0) | 2024.12.28 |
[UE] Delegate (델리게이트) / 발행 구독 패턴 (0) | 2024.12.26 |