게임 개발/Unreal Engine

[UE4] TArray 퍼포먼스 최적화

지노윈 2022. 4. 16. 15:48
반응형

https://www.unrealengine.com/ko/blog/optimizing-tarray-usage-for-performance?lang=ko 

 

Optimizing TArray Usage for Performance

언리얼 엔진에서 TArray 엘리먼트 유형별 크기가 동적으로 변하는 배열입니다. TArray 는 프로그래머에게 매우 편리하며, 코드베이스에 *많이* 사용됩니다. 하지만 미묘한 퍼포먼스 문제가 생길 수

www.unrealengine.com

 

압축된 메모리 공간에서 엄청 빠른 엘리먼트 반복처리를 원하는 경우, TArray 가 좋은 선택입니다. 하지만 코드를 작성하면서 추가, 제거 등의 작업에 대한 영향을 주의할 필요가 있습니다. 

 

- Reserve를 적절히 사용하면 메모리 할당 시도 회수를 줄일 수 있습니다.

- 함수 파라미터로 받을때는 레퍼런스(&)를 사용합시다 그렇지 않으면 값 복사가 일어 납니다.

- 엘리먼트 삭제시 RemoveAtSwap사용으로 제거시 이 공간을 메우기 위한 엘리먼트들의 이동을 피할 수 있습니다.

// 초기 배열:
// 0, 1, 2, 3, 4, 5, 6, 7, 8, 9

// (인덱스 3 위치의 엘리먼트를 제거하고, 마지막 엘리먼트와 맞바꿀 수 있도록 합니다)
Array.RemoveAtSwap(3);

// 엘리먼트 제거중인 임시 상태
// 0, 1, 2, _, 4, 5, 6, 7, 8, 9
// 엘리먼트 9 와 기존 3 이 있던 자리를 맞바꿉니다.
// 0, 1, 2, 9, 4, 5, 6, 7, 8

마지막 엘리먼트가 빈 공간을 차지하여 성능이 향상됩니다.

- 메모리 청소 제어로 퍼포먼스 향상 할 수 있습니다.

삭제시 매번 메모리 제어 하는 것이 아니라 마지막 한번 메모리 청소를 해줍니다.

void RemoveAtSwap(int32 Index, int32 Count = 1, bool bAllowShrinking = true)

bAllowShringKing을 false로 주었고 루프가 끝난 다음 Shrink 호출 합니다.

void RemoveEvenValues(TArray<int32>& Numbers)
{
	for (int32 Index = 0; Index < Numbers.Num(); Index++)
	{
		if (Numbers[Index] % 2 == 0)
		{
			Numbers.RemoveAtSwap(Index, 1, false);
			Index--;   // since we need to process this index again!
		}
	}
	
	// 옵션: 값 제거 후 빈 공간을 되찾습니다.
	Numbers.Shrink();
}

- TArray의 크기를 완벽히 알 경우 TInlineAllocator를 사용하여 힙 할당을 피해서 성능을 높일 수 있습니다.

 

TArray<Shape*> MyShapeArray;
// 다음과 같이 선언하면 동적 할당이 일어나지 않습니다.
TArray<Shape*, TInlineAllocator<16>> MyShapeArray;

- typedef를 사용하여 쉽게 사용합시다

typedef TArray<Shape*, TInlineAllocator<16>> ShapeArrayType;

// 쉽게 사용, 선언
ShapeArrayType MyShapeArray;

// 쉽게 사용, for에서
for (ShapeArrayType::TIterator Iter(MyShapeArray); Iter; ++Iter)
{
	Shape* MyShape = *Iter;
	MyShape->Draw();
}

// auto 사용으로 단순화 할 수도 있음
for (auto Iter = MyShapeArray.CreateIterator(); Iter; ++Iter)

for (auto* MyShape : MyShapeArray)
{
	MyShape->Draw();
}