Version: 2019.3
메모리
에셋 검사

코루틴

코루틴은 다른 스크립트 코드와 다르게 실행됩니다. 대부분의 스크립트 코드는 단일 위치의 성능 트레이스 내, 특정 Unity 콜백 호출 아래에 나타납니다. 반면, 코루틴의 CPU 코드는 항상 트레이스의 두 곳에서 나타납니다.

코루틴의 모든 시작 코드(코루틴 메서드의 시작부터 첫 번째 yield가 나타나는 곳까지의 코드)는 트레이스에서 나타나고, 트레이스에서 코루틴이 시작됩니다. 보통 StartCoroutine 메서드가 호출되는 곳에서 나타납니다. Unity 콜백(IEnumerator를 반환하는 Start 콜백 등)에서 생성된 코루틴은 각각의 Unity 콜백에서 최초로 나타납니다.

코루틴의 나머지 모든 코드(즉 다시 재개되는 시점에서부터 실행이 종료될 때까지의 코드)는 Unity 메인 루프에 있는 DelayedCallManager 행에 나타납니다.

왜 이러한 현상이 일어나는지 이해하려면 코루틴이 실제로 어떻게 실행되는지 생각해 보아야 합니다.

코루틴은 C# 컴파일러가 자동으로 생성한 클래스의 인스턴스에 의해 작동합니다. 이 오브젝트는 프로그래머에게 하나로 간주되는 메서드를 여러 번 호출하는 코루틴의 상태를 추적하는 데 필요합니다. 코루틴의 로컬 범위 변수는 yield 호출이 진행되는 동안 유지되어야 하기 때문에 변수는 생성된 클래스에 위치하게 되며, 코루틴이 작동되는 동안 힙에 할당된 상태로 남아 있습니다. 오브젝트는 코루틴의 내부 상태를 추적하여 yield 호출 이후에 코루틴이 재개될 때 코드의 어느 부분부터 재개할 것인지를 기억합니다.

그렇기 때문에 코루틴을 시작할 때 발생하는 메모리 사용량은 고정된 오버헤드 비용에 로컬 범위 변수의 크기를 합한 양과 동일합니다.

코루틴을 시작하는 코드는 이 오브젝트를 생성하고 호출하며, 그 이후 Unity의 DelayedCallManager가 코루틴의 yield 조건이 만족될 때마다 다시 오브젝트를 호출합니다. 코루틴은 보통 다른 코루틴의 외부에서 시작하기 때문에 코루틴 실행 비용은 위에서 설명한 두 위치로 나뉩니다.

위 스크린샷에서 DelayedCallManagerPopulateCharacters, AsyncLoadLoadDatabase를 비롯한 여러 개의 다른 코루틴을 다시 시작합니다.

가능한 경우 일련의 작업을 최대한 적은 수의 개별 코루틴으로 압축하는 것이 좋습니다. 코루틴을 중첩하면 코드 명료성을 높이고 유지관리가 용이하지만, 코루틴 추적(tracking) 오브젝트로 인해 더 많은 메모리가 소모됩니다.

코루틴이 매 프레임마다 실행되고 오래 실행되는 작업에서 이익이 되지 않는 경우, 일반적으로 코루틴을 Update 또는 LateUpdate 콜백으로 대체하면 더 쉽게 읽을 수 있습니다. 특히 오래 실행되거나 무한 루프되는 코루틴의 경우 더욱 그렇습니다.

StopCoroutineStopAllCoroutines를 사용하여 코루틴을 중지할 수 있습니다. 또한 SetActive(false)로 인해 연결된 게임 오브젝트가 비활성화될 때에도 코루틴이 중지됩니다. Destroy(example)(여기서 example은 MonoBehaviour 인스턴스)을 호출하면 OnDisable이 즉시 트리거되고 코루틴이 처리되므로 효과적으로 중지할 수 있습니다. 마지막으로, OnDestroy는 프레임이 끝날 때 호출됩니다.

MonoBehaviour 인스턴스에서 enabled를 false로 설정하여 MonoBehaviour를 비활성화한 경우에는 코루틴이 중지되지 않습니다.

코루틴은 스레드가 아니라는 점을 명심하십시오. 코루틴의 동기 작업은 여전히 메인 스레드에서 실행됩니다. 목표가 메인 스레드에서 소비되는 CPU 시간을 줄이는 것이라면 다른 스크립트 코드에서와 마찬가지로 코루틴의 작업 차단을 방지하는 것이 중요합니다.

코루틴은 HTTP 전송, 에셋 로드, 파일 I/O 완료 등을 기다리는 것과 같이 긴 시간을 필요로 하는 비동기 작업에 사용하는 것이 가장 유용합니다.

메모리
에셋 검사