Unity 가비지 컬렉터 최적화 가이드
이 문서는 Unity에서 가비지 컬렉션을 관리하고 최적화하는 방법에 대해 설명합니다. 최적화된 메모리 관리는 성능을 높이고 애플리케이션의 원활한 실행을 보장합니다.
목차
- 개요
- 가비지 컬렉션의 개념
- 임시 할당 관리
- 재사용 가능한 오브젝트 풀
- 반복된 스트링 연결 최적화
- 컬렉션과 배열 재사용
- 박싱 문제 피하기
- 배열 기반 Unity API 최적화
- 비할당 API 대안 사용
개요
가비지 컬렉션은 Unity가 자동으로 메모리를 관리하는 방법입니다. 성능을 최적화하기 위해 애플리케이션이 가비지 컬렉터를 자주 트리거하지 않도록 주의해야 합니다.
가비지 컬렉션의 개념
가비지 컬렉션은 메모리 누수를 방지하고 메모리 관리를 자동화합니다. 그러나 잦은 호출은 성능을 저하시킬 수 있습니다.
- CPU 시간 소모: 가비지 컬렉터가 활성화될 때 CPU 시간이 많이 소모됩니다.
임시 할당 관리
애플리케이션은 일반적으로 매 프레임마다 임시 데이터를 관리되는 힙에 할당합니다. 예를 들어, 매 프레임 1KB를 할당하는 경우 1초에 60KB를 할당하게 됩니다. 이를 최소화하려면 프레임당 메모리 할당량을 줄여야 합니다.
재사용 가능한 오브젝트 풀
오브젝트 풀링을 활용하면 불필요한 오브젝트 생성을 줄일 수 있습니다. 예를 들어, 발사체 오브젝트를 각 프레임마다 새로 생성하지 말고 기존 오브젝트를 비활성화하고 재사용하는 방법입니다.
코드 예제
using System.Collections.Generic;
using UnityEngine;
public class ExampleObjectPool : MonoBehaviour {
public GameObject PrefabToPool;
public int MaxPoolSize = 10;
private Stack<GameObject> inactiveObjects = new Stack<GameObject>();
void Start() {
if (PrefabToPool != null) {
for (int i = 0; i < MaxPoolSize; ++i) {
var newObj = Instantiate(PrefabToPool);
newObj.SetActive(false);
inactiveObjects.Push(newObj);
}
}
}
public GameObject GetObjectFromPool() {
while (inactiveObjects.Count > 0) {
var obj = inactiveObjects.Pop();
if (obj != null) {
obj.SetActive(true);
return obj;
}
}
return null;
}
public void ReturnObjectToPool(GameObject objectToDeactivate) {
if (objectToDeactivate != null) {
objectToDeactivate.SetActive(false);
inactiveObjects.Push(objectToDeactivate);
}
}
}
반복된 스트링 연결 최적화
C#의 문자열은 변경할 수 없는 타입입니다. 반복적으로 문자열을 연결하면 많은 임시 문자열이 생성되므로 StringBuilder
를 사용하는 것이 좋습니다.
예제 개선 방법
using UnityEngine;
using System.Text;
public class ExampleScript : MonoBehaviour {
private StringBuilder _sb = new StringBuilder(16);
string ConcatExample(string[] stringArray) {
_sb.Clear();
for (int i = 0; i < stringArray.Length; i++) {
_sb.Append(stringArray[i]);
}
return _sb.ToString();
}
}
컬렉션과 배열 재사용
시스템의 메모리를 효율적으로 사용하기 위해 기존의 배열이나 컬렉션을 재사용하는 것이 좋습니다. Clear()
메서드를 사용하여 리스트의 내용을 지우고 재사용할 수 있습니다.
예제
List<float> m_NearestNeighbors = new List<float>();
void Update() {
m_NearestNeighbors.Clear();
findDistancesToNearestNeighbors(m_NearestNeighbors);
m_NearestNeighbors.Sort();
}
박싱 문제 피하기
박싱은 값 타입을 레퍼런스 타입으로 변환할 때 발생하는 불필요한 메모리 할당입니다. 이러한 박싱을 피하려면 값 타입을 직접 사용하도록 합니다.
예제
int x = 1;
object y = new object();
y.Equals(x); // 박싱 발생
배열 기반 Unity API 최적화
Unity API에서 배열을 반환할 때 매번 새로운 사본을 생성합니다. 이를 방지하려면 배열을 한 번만 할당하고 재사용해야 합니다.
예제
void Update() {
var vertices = mesh.vertices;
for(int i = 0; i < vertices.Length; i++) {
float x = vertices[i].x;
float y = vertices[i].y;
float z = vertices[i].z;
}
}
비할당 API 대안 사용
Unity API 중 일부는 메모리 할당을 발생시키지 않는 대안이 있습니다. 가능한 경우 이러한 API를 사용하는 것이 좋습니다.
할당 API | 비할당 API 대안 |
---|---|
Physics.RaycastAll | Physics.RaycastNonAlloc |
Animator.parameters | Animator.parameterCount |
Renderer.sharedMaterials | Renderer.GetSharedMaterials |
이와 같은 최적화 방법들을 통해 Unity 프로젝트의 성능을 향상시키고 가비지 컬렉터의 영향을 최소화할 수 있습니다.