유니티 가비지 컬렉션 최적화하기6 – 번역
유니티에서 가비지 컬렉션 최적화하기6
– 원문 링크 –
이전글 – 불필요한 힙 할당을 발생시키는 주요 원인 2
가비지 컬렉션의 영향을 최소하하기 위한 코드의 구조화 (Structuring our code to minimize the impact of garbage collection)
코드를 구조화하는 방식은 가비지 컬렉션에 영향을 줄 수 있습니다. 작성한 코드가 힙 할당을 발생시키지 않더라도, 가비지 컬렉터의 작업에 부하를 줄 수 있습니다.
불필요하게 가비지 컬렉터의 작업에 부하를 줄 수 있는 방법 중 하나는, 검사할 필요가 없는 항목을 검사하도록 요청하는 것입니다.
구조체는 값 타입 변수입니다. 하지만, 참조 타입 변수를 갖는 구조체의 경우, 가비지 컬렉터는 구조체 전체를 검사해야 합니다.
이때 이런 구조체의 배열이 많은 경우, 가비지 컬렉터가 점검해야하는 작업이 많이 발생할 수 있습니다.
아래 예제에서, 구조체는 문자열을 포함하며, 문자열은 참조 타입입니다. 이제 가비지 컬렉터가 실행되면, 이 구조체 배열 전체를 검사해야합니다.
public struct ItemData { public string name; public int cost; public Vector3 position; } private ItemData[] itemData;
아래 예제에서는, 별도의 배열에 데이터를 저장합니다.
가비지 컬렉터가 실행되면, 문자열 배열에 대해서만 검사를 진행하고, 나머지 배열은 무시할 수 있습니다. 이는 가비지 컬렉터가 해야할 일을 줄입니다.
private string[] itemNames; private int[] itemCosts; private Vector3[] itemPositions;
가비지 컬렉터의 작업에 불필요한 부하를 줄 수 있는 또 다른 방법은, 불필요한 오브젝트 참조 값을 갖는 것입니다.
가비지 컬렉터가 힙 상의 오브젝트에 대한 참조를 검색하려면, 코드에서 사용 중인 오브젝트를 모두 검사해야합니다.
코드에서 오브젝트의 참조가 적다는 것은, 힙 상의 전체 오브젝트의 수를 줄이지 않더라도, 처리할 작업량이 적다는 것을 의미합니다.
아래 예제에는, 대화 상자를 띄우는 클래스가 있습니다. 사용자가 대화 상자를 다보면, 다음 대화상자가 열립니다.
이 코드에는 다음에 표시되어야하는 DialogData의 인스턴스에 대한 참조가 포함되어 있습니다. 이는 가비지 컬렉터가 작업의 일부로, 이 참조를 검사해야 한다는 것을 의미합니다:
public class DialogData { private DialogData nextDialog; public DialogData GetNextDialog() { return nextDialog; } }
아래 예제에서는, 다음에 표시되어야하는 DialogData의 인스턴스 값 대신, 그 인스턴스를 찾을 수 있는 식별자(identifier)를 반환하도록 코드를 재구성 했습니다. 이 값은 오브젝트 참조가 아니기 때문에, 가비지 컬렉터가 실행되는데 소모되는 시간을 추가하지 않습니다.
public class DialogData { private int nextDialogID; public int GetNextDialogID() { return nextDialogID; } }
이 예제 자체는 간단한 내용을 다룬 예제에 불과합니다.
하지만, 만드는 게임에서 다수의 오브젝트를 참조하는 오브젝트가 많은 경우, 코드를 이런 방식으로 재구성해서 힙의 복잡도를 현저하게 줄일 수 있습니다.
Timing garbage collection
수동으로 가비지 컬렉션 실행하기 (Manually forcing garbage collection)
마지막으로, 수동으로 가비지 컬렉션을 실행시킬 수 있습니다. 힙 메모리가 할당되었지만, 더이상 사용되지않고(예: 코드에서 애셋을 로드할때 가비지를 생성한 경우), 가비지 컬렉터로 인한 화면 멈춤이 플레이어에게 영향을 미치지 않는다는 것을 알고 있는 경우(예: 로딩 화면이 보여지는 동안에), 아래 코드를 이용해서 가비지 컬렉션을 요청할 수 있습니다:
System.GC.Collect();
이 코드는 가비지 컬렉터가 실행되도록 강제하며, 이를 통해서 원하는 시점에 사용하지않는 메모리를 회수할 수 있습니다.
결론 (Conclusion)
유니티에서 가비지 컬렉션이 동작하는 방식에 대해서 살펴봤습니다.
또한 성능 문제를 일으킬 수 있는 원인과 가비지 컬렉션이 게임에 미치는 영향을 최소화 하는 방법에 대해서도 살펴봤습니다.
여기에서 배운 지식과 프로파일링 도구를 이용해서, 가비지 컬렉션과 관련된 성능 문제를 해결하고, 메모리를 효율적으로 관리할 수 있도록 게임을 구성할 수 있습니다.
아래 링크는 이 글에서 다룬 주제들에 대한 자세한 정보를 제공합니다.
Further reading
Memory management and garbage collection in Unity
Unity Manual: Understanding Automatic Memory Management
Gamasutra: C# Memory Management for Unity Developers by Wendelin Reich
Gamasutra: C# memory and performance tips for Unity by Robert Zubek
Gamasutra: Reducing memory allocations to avoid Garbage Collection on Unity by Grhyll JDD
Gamasutra: Unity Garbage Collection Tips and Tricks by Megan Hughes
Boxing
MSDN: Boxing and Unboxing (C# Programming Guide)
Object pooling
Unity Learn: Object Pooling Tutorial
Wikipedia: Object Pool Pattern
Strings
Best Practices for Using Strings in the .NET Framework
내용 끝까지 읽어주셔서 감사합니다.
배너 클릭은 저에게 많은 힘이 됩니다.
감사합니다 🙂