Unity는 스키닝, 배칭, 물리 연산, 사용자 스크립트, 파티클 등에 있어 CPU(x86의 SSE나 ARM의 NEON 등 SIMD 일부에 고도로 최적화)에 의존합니다.
GPU는 셰이더, 드로우콜, 이미지 이펙트에 사용됩니다.
대부분의 문제(80%)가 몇 가지 핵심 원인(20%)에 의해 발생합니다. 에디터 프로파일러를 사용해 가장 프로세서 집약적인 함수 호출을 식별하고 이를 먼저 최적화해야 합니다. 많은 경우 몇 가지 핵심 함수를 최적화하는 행위만으로도 전체적인 실행 속도를 크게 향상시킬 수 있습니다.
함수가 꼭 필요한 경우에만 실행되고 있는지 확인해야 합니다. 예를 들어 OnBecameVisible 와 OnBecameInvisible 같은 이벤트를 활용해 언제 오브젝트가 보이지 않고 업데이트를 피하는지 감지할 수 있습니다. 코루틴은 정기적인 업데이트가 필요하지만 매 프레임마다 실행될 필요 없는 코드를 호출할 때 유용합니다.
// Do some stuff every frame:
void Update () {
}
//Do some stuff every 0.2 seconds:
IEnumerator SlowUpdate () {
while (true) {
//do something
yield return new WaitForSeconds (0.2f);
}
}
.NET System.Threading.Thread 클래스로 별도 스레드의 과중한 계산을 처리할 수 있습니다. 이에 다수의 코어를 실행할 수 있기는 하나 Unity API는 스레드에서 안전하지 않으므로 입력물과 결과물을 버퍼링해야 하며 Unity API 호출의 활용을 위해 이것을 읽고 메인 스레드에 할당해야 합니다.
모든 사용자 코드가 프로파일러에 표시되지는 않습니다. 하지만 Profiler.BeginSample 및 Profiler.EndSample 을 활용해 필요한 사용자 코드를 프로파일러에 표시할 수 있습니다.
현재는 Unity 에디터 프로파일러에 GPU 데이터가 표시되지 않습니다. Unity는 해당 데이터가 표시되도록 하드웨어 제조사와 작업을 진행 중이며 Tegra 디바이스가 처음으로 에디터 프로파일러에 표시됩니다.
PowerVR은 타일 기반의 디퍼드 렌더러이기 때문에 드로우 콜마다 GPU 타이밍을 얻는 것은 불가능합니다. 하지만 Unity 내장 프로파일러(결과물을 Xcode 아웃풋에 출력)를 활용해 전체 씬의 GPU 시간을 알 수는 있습니다. 현재 Apple의 툴은 GPU와 관련 파트가 얼마나 바쁜지 알려주지만 밀리초 단위로는 알 수 없습니다.
PVRUniSCo는 전체 셰이더의 사이클과 셰이더 코드 각 행의 대략적 사이클을 알려줍니다. Windows와 Mac 모두에 해당됩니다. Apple 드라이버의 실행 사항과 정확히 일치하지는 않지만 대략적인 지표로서는 괜찮습니다.
Tegra에서 NVIDIA는 원하는 바를 모두 실현할 수 있게 해주는 환상적인 퍼포먼스 툴을 제공합니다. 드로우 콜 별 GPU 시간, 셰이더 별 사이클, 포스 2x2 텍스처, Null 뷰 사각형이 Windows, OSX, Linux에서 실행됩니다. PerfHUD ES는 소비자의 디바이스에서 손쉽게 작동하지 않으므로 NVIDIA의 개발 보드가 필요합니다.
Qualcomm은 탁월한 Adreno 프로파일러를 Windows용으로만 제공하지만 소비자의 디바이스에서 작동합니다. 타임라인 그래프, 프레임 캡처, 프레임 디버그, API 호출, 셰이더 분석기, 실시간 편집 기능을 갖추고 있습니다.
내부 프로파일러는 모듈 별로 훌륭한 개요를 제공합니다.
Unity 프로파일러가 사용하는 포트는 다음과 같습니다.
네트워크 노드에서 액세스 가능해야 합니다. 다시 말해 프로파일하려는 디바이스는 프로파일러를 사용하는 Unity 에디터가 있는 기기의 포트를 볼 수 있어야 합니다.
메모리에는 모노 메모리와 Unity 메모리의 두 가지 타입이 있습니다.
모노(Mono) 메모리는 스크립트 오브젝트, Unity 오브젝트의 래퍼(게임 오브젝트, 에셋, 컴포넌트 등)를 처리합니다. 할당이 사용 가능한 메모리에 맞지 않을 때나 System.GC.Collect() 가 호출됐을 때 가비지 컬렉터가 메모리를 정리합니다.
메모리는 힙 블록에 할당됩니다. 할당된 블록에 데이터를 저장할 수 없을 때 메모리가 더 할당될 수 있습니다. 힙 블록은 응용 프로그램이 닫힐 때까지 모노에 보관됩니다. 다시 말해 모노는 사용된 메모리를 OS(Unity 3.x)로 릴리스하지 않습니다. 일정 수준의 메모리를 할당하고 나면 모노용으로 확보해 OS에서 사용할 수 없습니다. 릴리스 후에도 내부적으로 모노용으로만 가능하며 OS에서는 사용할 수 없습니다. 프로파일러의 힙 메모리 값은 오로지 증가하며 절대 줄지 않습니다.
시스템이 할당한 힙 블록에 새 데이터를 저장하지 못하면(예를 들어 단편화의 이유로) 모노는 “GC”를 호출하고 새로운 힙 블록을 할당할 수 있습니다.
“힙 섹션이 지나치게 많다”는 뜻은 단편화나 과중한 사용 때문에 모노 메모리를 전부 소모했다는 의미입니다.
System.GC.GetTotalMemory
로 모노 메모리의 총 사용량을 알 수 있습니다.
일반적인 조언을 드리자면 가능한 한 작은 할당을 사용해야 합니다.
Unity 메모리는 에셋 데이터(텍스처, 메시, 오디오, 애니메이션 등), 게임 오브젝트, 엔진 내부(렌더링, 파티클, 물리 등)를 처리합니다.
Profiler.usedHeapSize
로 Unity 메모리 총 사용량을 알 수 있습니다.
아직 툴이 준비되지 않았으나, 다음을 활용할 수 있습니다.
또한, Unity API 호출로 자체적인 툴을 만들 수 있습니다.
FindObjectsOfTypeAll (type : Type) : Object[]
FindObjectsOfType (type : Type): Object[]
GetRuntimeMemorySize (o : Object) : int
GetMonoHeapSize
GetMonoUsedSize
Profiler.BeginSample/EndSample
- 자체적인 코드를 프로파일합니다.UnloadUnusedAssets () : AsyncOperation
System.GC.GetTotalMemory/Profiler.usedHeapSize
로드된 오브젝트에 대한 참조 - 이를 파악할 방법은 없지만 public 변수에 대해 “씬에서 레퍼런스 찾기”를 차선책으로 활용할 수 있습니다.
OnGUI()
를 사용하지 마십시오. 프레임마다 여러 번 실행되어 뷰를 완전히 새로 그리며 대량의 메모리 할당 호출을 불러와 결과적으로 가비지 컬렉션이 실행되게 합니다.System.GC.Collect()
라는 .Net 함수를 쓸 수 있습니다.이론적으로는 메모리가 충분하지만 어느 시점에 게임이 “메모리 부족”으로 크래시할 수도 있습니다. 크래시가 일어나면 평상시 게임 메모리 사용량과 할당된 메모리 크기를 비교해볼 수 있습니다. 두 수치가 비슷하지 않다면 메모리 스파이크가 일어납니다. 그 원인은 다음과 같습니다.