코드 짤때는 GC호출을 최소화해야함


그러려면 가비지를 만드는일을 최소화해야하는데


그 중 Dictionary의 key를  Enum으로 쓰는 경우를 테스트 해봄



* Init


using System.Collections;

using System.Collections.Generic;

using UnityEngine;


enum TestEnum

{

    A,

}


public class DictionaryEnumTest : MonoBehaviour

{


    Dictionary<TestEnum, string> testEnumDic;

    Dictionary<int, string> testIntDic;


    // Use this for initialization

    void Start()

    {

        InitEnumDic();

        InitIntDic();

    }


    void InitEnumDic()

    {

        testEnumDic = new Dictionary<TestEnum, string>();

    }


    void InitIntDic()

    {

        testIntDic = new Dictionary<int, string>();

    }


}


위 코드로 테스트한 프로파일러 결과임




빨간색 칠해둔것을 보면 Enum을 Key로 한 Dictionary가 GC Alloc 0.2KB 더 많이함

양이 많지는 않음(빈번하면 안좋음)




* Add


아까 생성한 두 Dictionary에 각각 값을 넣어봤음


using System.Collections;

using System.Collections.Generic;

using UnityEngine;


enum TestEnum

{

    A,

}


public class DictionaryEnumTest : MonoBehaviour

{


    Dictionary<TestEnum, string> testEnumDic;

    Dictionary<int, string> testIntDic;


    // Use this for initialization

    void Start()

    {

        InitEnumDic();

        InitIntDic();


        AddEnumDic();

        AddIntDic();

    }


    void InitEnumDic()

    {

        testEnumDic = new Dictionary<TestEnum, string>();

    }


    void InitIntDic()

    {

        testIntDic = new Dictionary<int, string>();

    }


    void AddEnumDic()

    {

        testEnumDic.Add(TestEnum.A, "A");

    }


    void AddIntDic()

    {

        testIntDic.Add(1, "A");

    }

}



20B를 생성했음..

Dictionary에 값이 많이 들어간다 생각하면 개손해임



* TryGetValue


가장 빈번할것으로 예상되는 값 찾기


using System.Collections;

using System.Collections.Generic;

using UnityEngine;


enum TestEnum

{

    A,

}


public class DictionaryEnumTest : MonoBehaviour

{

    Dictionary<TestEnum, string> testEnumDic;

    Dictionary<int, string> testIntDic;


    // Use this for initialization

    void Start()

    {

        InitEnumDic();

        InitIntDic();


        AddEnumDic();

        AddIntDic();


        GetValueEnumDic();

        GetValueIntDic();

    }


    void InitEnumDic()

    {

        testEnumDic = new Dictionary<TestEnum, string>();

    }


    void InitIntDic()

    {

        testIntDic = new Dictionary<int, string>();

    }


    void AddEnumDic()

    {

        testEnumDic.Add(TestEnum.A, "A");

    }


    void AddIntDic()

    {

        testIntDic.Add(1, "A");

    }


    void GetValueEnumDic()

    {

        string result;

        testEnumDic.TryGetValue(TestEnum.A, out result);

    }


    void GetValueIntDic()

    {

        string result;

        testIntDic.TryGetValue(1, out result);

    }

}




Key가 int인거는 0생성했는데

enum인거는 1번찾는데 60B 생성함... 핵손해


장난삼아 10만번 돌려봄




게임마다 다르겠지만 10만번을 찾을일이 게임에서 많지는 않을 것 같은데 아무튼 5.7MB나 생성함








* 해결책


https://stackoverflow.com/questions/26280788/dictionary-enum-key-performance

위 링크를 보고 함


저 중에서 가장 쉬워보이는 1번 솔루션을 적용해봄


첫번째 프로파일러 스크린샷인데 저걸 열어보면 EqualityComparer라는애가 있음

키를 비교할 때 enum이기때문에 비교할 때 Boxing UnBoxing하는데 비용이 크다고 함

그래서 비교하는애를 Dictionary 생성할 때 넣어주는거임


public struct MyEnumCOmparer : IEqualityComparer<MyEnum>
{
    public bool Equals(MyEnum x, MyEnum y)
    {
        return x == y;
    }

    public int GetHashCode(MyEnum obj)
    {
        // you need to do some thinking here,
        return (int)obj;
    } 

}


new Dictionary<MyEnum, int>(new MyEnumComparer());


이 코드를 나의 테스트 코드에 맞게 바꾸고 테스트 함


using System.Collections;

using System.Collections.Generic;

using UnityEngine;


public enum TestEnum

{

    A,

}


public struct TestEnumComparer : IEqualityComparer<TestEnum>

{

    public bool Equals(TestEnum x, TestEnum y)

    {

        return x == y;

    }


    public int GetHashCode(TestEnum obj)

    {

        return (int)obj;

    }

}


public class DictionaryEnumTest : MonoBehaviour

{

    Dictionary<TestEnum, string> testEnumDic;


    // Use this for initialization

    void Start()

    {

        InitEnumDic();

        AddEnumDic();

        GetValueEnumDic();

    }


    void InitEnumDic()

    {

        testEnumDic = new Dictionary<TestEnum, string>(new TestEnumComparer());

    }

    

    void AddEnumDic()

    {

        testEnumDic.Add(TestEnum.A, "A");

    }

    

    void GetValueEnumDic()

    {

        string result;

        for(int i=0;i<100000;i++)

            testEnumDic.TryGetValue(TestEnum.A, out result);

    }    

}




10만번 Get할때 가비지 한개도 안생기고 Add할때도 사라짐


개이득


생성할 때도 없애기 위해서 Dictionary key값을 int로 바꾸는거는 너무 가독성면에서나 작업량에서나 손해고


Key는 enum으로 쓰면서 위 방법을 사용하면 어느정도 쉽고 빠르게 해결 가능





+ Recent posts