Profiling
- 최적화할때 프로파일링은 필수
- 최적화는 수시로 해야 한다.
- 프로토타입은 할 필요 없다. 어차피 바뀌는게 많으므로
- 맹목적으로 하지 말것
- 병목지점을 찾아서 최적화 지점을 알아야 한다
- 에디터가 아닌 모바일 타겟 디바이스에서 돌려봐야 한다.
- 성능이 다르기 때문에 병목지점이 다르다
- Xcode intstruments를 이용하면 유니티 프로파일링보다 더 디테일하게 볼 수 있다.
- 프로파일링 툴/디바이스가 모두 애플것이므로.
- 아이폰 성능 프로파일링을 위한 최고의 툴! Xcode Instrument로 게임 성능 측정하기
- 안드로이드는 스냅드래곤이나 Android Studio등 다양하게 있으니 확인해보자.
- Profiler Analyzer를 이용하면 프로파일링을 스냅샷하여 before after같은 성능 변화 추이를 볼 수 있다.
- 성능측정을 할땐 FPS에보다는 ms(milliseconds)를 이용하자
- ms는 1프레임을 그릴때 걸리는 시간을 1/1000초로 환산한것이다
- FPS = 1000/ms
- Ms = 1000/FPS
- 예를들어 특정 프레임이 총 30ms가 걸리는데…
- Rendering 5ms
- Update 5ms
- Phygics 20ms
- 라고 한다면 Phygic를 최적화하는것이 제일 효율적일 것이다.
- ms는 1프레임을 그릴때 걸리는 시간을 1/1000초로 환산한것이다
- 병목이 GPU bound인지, CPU bound인지 확인하자
- 모바일 디바이스는 발열에 주의하자
- 측정할때 쓰로틀링에 빠지면 신뢰할 수 없는 결과가 나온다
- 스마트폰과 태블릿은 해상도가 다르기 때문에 병목에 GPU bound가 생길수도 있으니 확인하자.
Memory
- Memory Profiler를 이용하자
- Texture보다는 RenderTexture와 Shader가 더 메모리를 사용하므로 최적화하는 Texture를 수정하는건 의미없다
- PC
- Storage를 메모리가 빌려쓸 수 있다. 그래서 게임이 16GB를 사용하는데 RAM이 8GB더라도 뻗지 않는다
- Mobile
- Storeage를 메모리로 쓸 수 없다. 그래서 모바일에서는 해당 RAM을 사용하면 OS에서 앱을 강제종료 시켜버린다
- GC는 항상 염두에 두자
- GC가 자주 도는것은 spike의 원인
- String
- JSON이나 XML을 사용할때 string을 파싱하는데 그 string이 GC의 대상이 된다
- 배포단계에서는 JSON이나 XML을 ScriptableObject로 변환하여 사용하는것이 좋다(자동화 추천)
- Animator
- Animator.SetBool 같은 함수에 파라미터로 string을 넘기는 것은 string이 GC의 대상이 된다. 대신 Id값을 넘기도록 하자.
- Id를 얻어오는 것은 Animator.StringToHash를 사용
- Unity Function calls
- Tag를 비교할 땐 GameObject.tag == 보다는 GameObject.CompareTag를 사용하는것이 좋다. Tag는 garbage를 발생시킨다
- Coroutine
- yield return new WaitForSeconds 보다는 yield return cachaedWaitForSeconds 처럼 캐시하여 사용하자
- Adaptive Performance(삼성 디바이스)
- 현재 쓰로틀링 직전인지, GPU바운드인지 등등의 상태를 알 수 있어서 런타임 최적화를 할 수 있으니 적극 활용하자
- 빈 함수는 제거하자
- Start, Update문같은것도 빈 함수로 두면 영향을 끼친다
- Define symbol을 활용하자
- System.Diagnostics.Conditional 을 활용하자
- Componet사용 주의
- AddComponent는 사용을 지양하자.
- GetComponet는 캐시해서 사용하자
- 오브젝트 풀 사용
- 주의할점은 오브젝트 풀을 사용하면서 Active/Deactive식으로 나눈 후 부모를 바꾸지 말것.
- SetParent가 생각보다 성능을 잡아먹는다.
- ScriptableObject 사용하기
- MonoBehaviour를 상속받아서 프리팹으로 사용하게 되면 Serialized를 하게 된다
- ScriptableObject는 이미 Serialized가 되었기 때문에 성능적인 면, 관리적인 면에서 이득이다.
- Project Configuration
- 프로젝트 설정에는 선택해야하는 항목들이 많다
- 키워드는 "끄거나 줄여라"
- 프로젝트에 필요없는 것들은 끄거나 줄여야한다
- 끄자 - 중력센서, 등등
- 줄이자 - Auto Graphics API대신 원하는 플랫폼에 맞춰 추가
- 불필요한 physics 연산(auto simulation, auto sync transforms)은 사용하지 않는다
- Physics는 물리공간이 별도로 존재한다.
- Scene뷰의 객체들과 물리공간의 객체들은 데이터가 동기화되어야 하는데, auto sync transforms를 사용하면 자동으로 동기화를 시켜준다
-
- Application.targetFrameRate를 프로젝트별로 알맞게 설정한다(RPG=60, PUZZLE=30 ….)
- 큰 하이라키 구조는 피한다
- A부모에 A', A'', A''' 등등의 자식들이 많아질수록 A부모 transform이 움직였을때 자식들의 transform도 재계산이 이루어진다
- A부모와 B부모, C부모.. 등등 부모가 잘 쪼개어지면 각 부모를 멀티스레드 연산으로 병렬적으로 돌릴 수 있기 때문에 하이라키 구조를 잘 구성하자
- transform의 position, rotation등등 값들은 한번에 처리하는 것이 좋다
- 각 속성에 값을 set할때마다 transform연산이 일어난다
- 위의 큰 하이라키 구조라면 자식들의 모든 transform연산도 일어난다
- Transform.SetPositionAndRotation을 이용한다
- Instantiate(prafab, parent) 대신 Instantiate(prefab, parent, position, rotation) 을 사용하자
- Vsync는 꺼주자