이전 글에서 Xml 파싱 코드를 만들다 Enum.Parse를 그대로 사용했는데 이 부분에서 GC가 많이 발생해서 이 부분만 때어내서 글을 써볼까 합니다.
웬만한 상황에서는 Enum을 정수형으로 변환해서 저장하고 파싱 하는 게 가장 좋은 방법인데, Xml로 스크립팅을 하게 되는 경우 스크립팅을 하는 작업자분들이 정수형보다는 Enum의 이름으로 보는 게 작업하기 편해서 생각보다 많이 사용됩니다.
- 이전 글: https://coding-paper.tistory.com/6
- Enum.Parse함수: https://docs.microsoft.com/dotnet/api/system.enum.parse

문제

이전 글에서 작업했던 코드를 Unity Profiler에서 확인 했을 때의 스크린샷입니다.
GC.Alloc 호출 수도 어어어어엄청 많고 실제 할당된 메모리도 66.4MB면... 어우..
구현
using System;
using System.Collections.Generic;
public static class EnumUtility
{
static Dictionary<Type, Dictionary<string, object>> m_DicStringToEnum = new Dictionary<Type, Dictionary<string, object>>();
public static void CacheStringToEnum(Type type)
{
if (m_DicStringToEnum.ContainsKey(type) == true)
return;
m_DicStringToEnum.Add(type, new Dictionary<string, object>());
var names = System.Enum.GetNames(type);
var values = System.Enum.GetValues(type);
for (int i = 0; i < names.Length; i++)
{
var name = names[i];
var value = values.GetValue(i);
if (string.IsNullOrEmpty(name)) continue;
if (value == null) continue;
m_DicStringToEnum[type].Add(name, value);
}
}
public static TEnum EnumParse<TEnum>(string str) where TEnum : Enum
{
var type = typeof(TEnum);
CacheStringToEnum(type);
if (m_DicStringToEnum[type].ContainsKey(str) == false)
{
throw new FormatException();
}
return (TEnum)m_DicStringToEnum[type][str];
}
}
Enum.Parse에서 왜 GC가 발생하는지는 정확히는 모르겠지만, EnumUtility라는 static 클래스를 만들어서 Dictionary에 캐싱하여 string으로 찾도록 구현해두었습니다. (아마도 캐싱 없이 string을 만들고 버리고 반복해서 그런 게 아닐까 추측합니다)
자세한 코드는 GitHub에 올려두었습니다.
https://github.com/PieceOfPaper/CSharp_EnumUtility/blob/main/EnumUtility.cs
결과

- Calls: 1,600,240 -> 1,400,262 (199,978 감소)
- GC Alloc: 66.4 MB -> 60.7 MB (5.7 MB 감소)
전체에 비해서는 조금 감소했지만 Enum 이외에도 다른 곳에서 GC를 발생시키는 문제들이 많은 코드라 이 정도 결과면 충분하다고 생각됩니다.
Enum.Parse함수를 10만 번 호출하도록 구현되어 있었으니, Enum.Parse 한번 호출 때마다 GC.Alloc 호출 수가 2번씩 생긴다고 보면 되겠네요.
사실 Enum.Parse로 실제 프로젝트에서 고생해서 글로 남기게 되었습니다.
에디터에서는 별 문제없는데 안드로이드 빌드해서 테스트하니 엄청난 프레임드랍을 맛봤습니다..
'Unity Tips' 카테고리의 다른 글
Unity에서 패치 다운로드 만들기 2편 - UnityWebRequest 이용하여 만들기 (0) | 2022.05.07 |
---|---|
Unity에서 패치 다운로드 만들기 1편 - 패치 리스트 만들기 (0) | 2022.05.07 |
Unity에서 계층이 있는 데이터 저장 (JSON vs XML vs Scriptable Object) (0) | 2022.04.30 |
Unity에서 C++코드(cpp) Native Plug-ins 사용하기 (0) | 2022.03.27 |
Unity에서의 Singleton 3편 - Singleton끼리 서로 참조하는 문제 (0) | 2022.03.09 |