유니티 가비지 컬렉션 최적화하기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

 

내용 끝까지 읽어주셔서 감사합니다.
배너 클릭은 저에게 많은 힘이 됩니다.
감사합니다 🙂

 

RonnieJ

프리랜서 IT강사로 활동하고 있습니다. 게임 개발, C++/C#, 1인 기업에 관심이 많습니다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

Please turn AdBlock off

Notice for AdBlock users

Please turn AdBlock off