Unity Project Auditor가 지적하는 GC 할당 코드 정리
Unity Project Auditor로 프로젝트를 분석하면 GC 할당을 일으키는 코드가 Major issues로 분류된다. 지적 항목은 모두 GC Alloc에 관한 것이다. 매 프레임 불필요한 관리 메모리를 할당하면 가비지 컬렉터가 주기적으로 정리 작업을 하고, 그동안 게임이 멈칫하는 스파이크가 생긴다.
항목별 원인과 대안
섹션 제목: “항목별 원인과 대안”System.DateTime.Now
섹션 제목: “System.DateTime.Now”- 원인: 현재 시간대와 일광 절약 시간 정보까지 계산하므로 그만큼 CPU 연산이 더 든다.
- 대안: 시간대 계산이 필요 없으면
System.DateTime.UtcNow를 쓴다. 게임 내 시간이면Time.time이나Time.unscaledTime을 쓴다.
LINQ
섹션 제목: “LINQ”- 원인:
.Where(),.OrderBy(),.ToList()같은 호출은 내부에서 새 컬렉션을 만들고 함수를 반복 호출해 관리 메모리를 할당하고 CPU 연산도 늘어난다. - 대안:
Update()처럼 매 프레임 도는 코드에서는 쓰지 않는다.for·foreach로 직접 구현한다.
Component.GetComponentsInChildren()
섹션 제목: “Component.GetComponentsInChildren()”- 원인: 호출할 때마다 결과를 담을 새 배열을 만들어 돌려준다.
- 대안:
Awake()나Start()에서 한 번 호출해 결과를 저장해 두고 재사용한다. 매번 호출해야 하면 미리 만든 리스트를 채워 주는List<T>인자 오버로드를 쓴다.
Input.touches
섹션 제목: “Input.touches”- 원인: 접근할 때마다 현재 모든 터치 정보를 담은 새 배열을 만든다.
- 대안:
Input.touchCount로 터치가 있는지 먼저 확인하고,for문에서Input.GetTouch(i)로 하나씩 가져온다. 둘 다 배열을 할당하지 않는다.
Object.name
섹션 제목: “Object.name”- 원인: 네이티브(C++) 엔진에 있는 이름을 C#으로 가져오면서 매번 새 문자열을 만든다.
- 대안:
Update()에서 이름을 계속 비교해야 하면gameObject.CompareTag("Player")처럼 태그를 쓴다. 태그 비교는 문자열을 할당하지 않는다. 이름이 꼭 필요하면Awake()에서 변수에 저장해 둔다.
박싱(Boxing)
섹션 제목: “박싱(Boxing)”- 원인:
int같은 값 타입이 참조 타입 객체로 변환되면 관리 힙에 메모리가 할당된다. - 주요 발생 지점:
string.Format("점수: {0}", 123)에서int가object로 박싱된다.Debug.Log(myIntValue)(Unity 2021 이전 버전)List<object>에int나float를 넣을 때
- 대안:
string.Format대신 문자열 보간이나ToString()을 쓴다.List<object>대신List<int>처럼 타입이 명확한 제네릭 컬렉션을 쓴다.