Version: Unity 6.0 (6000.0)
언어 : 한국어
모든 함수 호출 계측
프로파일러 모듈 커스터마이즈

프로파일러 트레이스 분석

애플리케이션을 프로파일링할 때 흔히 발생할 수 있는 몇 가지 문제가 있습니다. 이 페이지에서는 몇 가지 일반적인 성능 문제의 원인을 조사하는 방법을 간략하게 설명합니다.

시작 트레이스 분석

시작 시간을 추적할 때는 두 가지 주요 메서드, 즉 UnityInitApplicationGraphicsUnityLoadApplication을 검사해야 합니다. 이 두 가지 메서드는 프로젝트의 설정, 에셋, 코드가 시작 시간에 영향을 미칠 수 있는 주요 부분입니다.

참고: 애플리케이션의 시작 시간은 플랫폼마다 다릅니다. 대부분의 플랫폼에서는 스플래시 화면이 표시되는 동안 시작됩니다.

iOS 기기에서 실행 중인 예시 Unity 프로젝트의 Instruments 트레이스
iOS 기기에서 실행 중인 예시 Unity 프로젝트의 Instruments 트레이스

위의 iOS 기기에서 실행되는 예시 Unity 프로젝트의 Instruments 트레이스 스크린샷에서 플랫폼별 startUnity 메서드의 UnityInitApplicationGraphicsUnityLoadApplication 메서드에 주목하십시오.

UnityInitApplicationGraphics는 그래픽스 기기를 설정하고 Unity의 많은 내부 시스템을 초기화하는 등 많은 내부 작업을 수행합니다. 또한 리소스 시스템에 포함된 모든 파일의 인덱스를 로드하여 리소스 시스템을 초기화합니다.

Unity의 리소스 시스템은 프로젝트의 Assets 폴더에 있는 Resources 폴더의 데이터에 모든 에셋 파일을 포함합니다. 여기에는 Resources 폴더의 자식 폴더에 있는 모든 파일이 포함됩니다. 따라서 리소스 시스템을 초기화하는 데 소요되는 시간은 애플리케이션 프로젝트의 Resources 폴더 내 파일 수에 따라 증가합니다.

UnityLoadApplication에는 프로젝트의 첫 번째 씬을 로드하고 초기화하는 메서드가 포함되어 있습니다. 여기에는 셰이더 컴파일, 텍스처 업로드, 게임 오브젝트 인스턴스화 등 첫 번째 씬을 표시하는 데 필요한 데이터의 역직렬화 및 인스턴스화가 포함됩니다. 또한 Unity는 첫 번째 씬에 있는 모든 MonoBehaviourAwake 콜백을 실행합니다.

이러한 프로세스는 프로젝트의 첫 번째 씬에 있는 Awake 콜백에 오래 실행되는 코드가 있으면 해당 코드가 프로젝트의 초기 시작 시간을 늦추는 원인이 될 수 있음을 의미합니다. 이 문제를 해결하려면 슬로우 코드를 제거하거나 애플리케이션 라이프사이클의 다른 곳에서 실행해야 합니다.

런타임 트레이스 분석

초기 시작 시간 이후에 캡처된 프로파일링 트레이스의 경우, PlayerLoop 메서드가 가장 중요합니다. 이는 Unity의 메인 루프이며, 그 안에 있는 코드는 프레임당 한 번 실행됩니다.

예시 Unity 프로젝트의 Instruments 트레이스
예시 Unity 프로젝트의 Instruments 트레이스

위 스크린샷은 PlayerLoop 내에서 성능에 가장 큰 영향을 미치는 몇 가지 메서드를 보여 줍니다. 참고: PlayerLoop 내 메서드 이름은 Unity 버전에 따라 다를 수 있습니다.

PlayerRender는 Unity의 렌더링 시스템을 실행하는 메서드입니다. 여기에는 오브젝트 컬링, 동적 배치 계산, GPU에 그리기 명령 제출이 포함됩니다. 이미지 효과나 렌더링 기반 스크립트 콜백(예: OnWillRenderObject)도 여기에서 실행됩니다. 일반적으로 프로젝트가 인터랙티브 상태일 때 가장 많은 CPU 시간이 소모됩니다.

BaseBehaviourManagerCommonUpdate의 세 가지 템플릿 버전을 호출합니다. 이는 현재 씬의 활성 게임 오브젝트에 연결된 MonoBehaviour 내 특정 콜백을 호출합니다.

  • CommonUpdate<UpdateManager>Update 콜백 호출
  • CommonUpdate<LateUpdateManager>LateUpdate 콜백 호출
  • 물리 시스템이 선택되어 있으면 CommonUpdate<FixedUpdateManager>FixedUpdate 호출

일반적으로 BaseBehaviourManager::CommonUpdate<UpdateManager> 메서드는 검사해야 할 가장 유용한 메서드입니다. 이 메서드는 Unity 프로젝트 내에서 실행되는 대부분의 스크립트 코드에 대한 엔트리 지점이기 때문입니다.

다음과 같이 유용한 여러 다른 메서드도 있습니다.

  • 프로젝트가 UGUI 시스템을 사용하는 경우 UI::CanvasManager가 여러 개의 다른 콜백을 호출합니다. 여기에는 프로파일러에 CanvasManager가 가장 자주 표시되는 두 가지 작업인 Unity UI의 일괄 계산 및 레이아웃 업데이트가 포함됩니다.
  • DelayedCallManager::Update코루틴을 실행합니다.
  • PhysicsManager::FixedUpdate는 PhysX 물리 시스템을 실행합니다. 이는 주로 PhysX 내부 코드 실행을 포함합니다. 현재 씬의 물리 오브젝트(예: RigidbodyCollider) 수는 PhysX의 내부 코드에 영향을 미칩니다. 여기에서도 특히 OnTriggerStayOnCollisionStay 같은 물리 기반 콜백이 나타납니다.

프로젝트가 2D 물리 시스템을 사용하는 경우 이는 Physics2DManager::FixedUpdate에서 유사한 호출 집합으로 나타납니다.

스크립트 메서드 분석

IL2CPP로 크로스 컴파일된 플랫폼에서 스크립트를 호출할 때 ScriptingInvocation 오브젝트를 포함하는 트레이스 줄을 찾습니다. 여기에서 Unity의 내부 네이티브 코드가 스크립트 런타임으로 전환되어 스크립트 코드를 실행합니다. 참고: 기술적으로 Unity가 IL2CPP를 통해 C# 코드를 실행하면 네이티브 코드가 됩니다. 그러나 이 크로스 컴파일된 코드는 주로__ IL2CPP__Unity에서 개발한 스크립팅 백엔드로, 여러 플랫폼용 프로젝트를 빌드할 때 Mono 대신 사용할 수 있습니다. 자세한 정보
See in Glossary
런타임 프레임워크를 통해 메서드를 실행하며 수작업으로 작성된 C++과는 유사하지 않습니다.

예시 Unity 프로젝트의 트레이스
예시 Unity 프로젝트의 트레이스

위의 스크린샷에서 RuntimeInvoker_Void 줄 아래에 중첩된 메서드는 Unity가 프레임당 한 번 실행한 크로스 컴파일된 C# 스크립트의 일부분입니다.

이 트레이스 줄의 이름은 원래 클래스의 이름 뒤에 밑줄이 있고 원래 메서드 이름을 붙인 것입니다. 이 예시 트레이스에서 EventSystem.Update, PlayerShooting.Update와 기타 여러 Update 메서드를 볼 수 있습니다. 이는 대부분의 MonoBehaviours에 있는 표준 Unity Update 콜백입니다.

이러한 메서드를 확장하여 어떤 메서드가 CPU 시간을 소비했는지 확인할 수 있습니다. 여기에는 프로젝트 내 다른 스크립트 메서드, Unity API, C# 라이브러리 코드가 포함됩니다.

위의 트레이스는 프레임당 한 번씩 전체 UI를 통해 레이캐스팅하는 StandaloneInputModule.Process 메서드를 보여 줍니다. 이 메서드는 터치 이벤트가__ UI__(사용자 인터페이스) 사용자가 애플리케이션과 상호 작용하도록 해 줍니다. Unity는 현재 3개의 UI 시스템을 지원합니다. 자세한 정보
See in Glossary
요소 위에 머무르고 있는지, UI 요소를 활성화했는지를 감지합니다. 모든 UI 요소를 반복하여 마우스의 위치가 경계 직사각형 안에 있는지 테스트하는 이 메서드는 리소스를 많이 소모합니다.

에셋 로드

CPU 트레이스에서 에셋 로딩을 식별할 수도 있습니다. 에셋 로드를 나타내는 메인 메서드는 SerializedFile::ReadObject입니다. 이 메서드는 파일의 바이너리 데이터 스트림을 Transfer라는 메서드를 통해 작동하는 Unity의 직렬화 시스템에 연결합니다. Transfer 메서드는 텍스처, MonoBehaviour, 파티클 시스템 같은 모든 에셋 유형에 적용됩니다.

씬 로딩 트레이스
씬 로딩 트레이스

위 스크린샷은 Unity가 씬을 로드하는 트레이스입니다. 씬을 로드할 때 Unity는 SerializedFile::ReadObject 아래의 다양한 Transfer 메서드 호출에 따라 씬 내 모든 에셋을 읽고 역직렬화합니다.

런타임 중에 성능이 저하되고 성능 트레이스에 SerializedFile::ReadObject가 상당한 시간을 사용한 것으로 표시되면 에셋 로드로 인해 프레임 속도가 감소했다는 뜻입니다. 참고: SerializedFile::ReadObject는 일반적으로 SceneManager, Resources 또는 AssetBundle API가 동기식 에셋 로드를 요청할 때 메인 스레드에 표시됩니다.

이러한 성능 저하를 해결하기 위해 에셋 로딩을 비동기식으로 만들거나(무거운 ReadObject 호출을 워커 스레드로 이동) 무거운 특정 에셋을 미리 로드할 수 있습니다.

Transfer 호출은 Unity가 오브젝트를 복제할 때도 표시됩니다(트레이스에 CloneObject 메서드로 표시됨). CloneObject 호출 아래에 Transfer 호출이 표시되면 Unity가 스토리지에서 에셋을 로드하지 않습니다. 대신 Unity는 이전 오브젝트의 데이터를 새 오브젝트로 전송합니다. 이를 위해 Unity는 이전 오브젝트를 직렬화하고 결과 데이터를 새 오브젝트로 역직렬화합니다.

모든 함수 호출 계측
프로파일러 모듈 커스터마이즈