[Unity E-Book] 모바일 게임 퍼포먼스 최적화하기(Profiling, Memory, Code Architecture)

2024. 5. 9. 16:18Unity

728x90
반응형

매일 그렇듯 짬을 내어 공부하다가 유니티 블로그의 최적화 글을 읽었는데 정리를 해서 메모해두면 너무 좋을 것 같아서 이번 글에 정리해본다.

 


 

" Optimize your mobile game performance: Tips on profiling, memory, and code architecture from Unity’s top engineers"

 

Optimize your mobile game performance: Tips on profiling, memory, and code architecture from Unity’s top engineers | Unity Blo

When profiling your game, we recommend that you cover both spikes and the cost of an average frame in your game. Understanding and optimizing expensive operations that occur in each frame can be more useful for applications running below the target frame r

blog.unity.com

 

 


 

 

Profiling

  • 이른 시점에, 자주, 타겟 디바이스에서 프로파일링 한다.
  • 에디터에서 프로파일링 하면 게임 내 다양한 시스템의 상대적 성능에 대한 아이디어를 얻을 수 있지만, 각 장치에서 프로파일링 하면 보다 정확한 인사이트를 얻을 수 있다.
  • 지원하려는 최고 / 최저 사양의 디바이스에서 모두 프로파일링 해야 한다.
  • 어플리케이션 빌드에서, Development Build를 선택하고 Autoconnect Profiler를 선택하여 프로파일링 한다.

  • Spike를 확인할 때 비싼 기능인 physics, AI, animation과 GC에 대해서 먼저 확인한다.
  • Profile Analyzer를 통해서 바뀐 부분에 대한 프로파일링을 비교한다.

 

 


 

 

Memory

  • GC가 자동적으로 돌아가는 상황에서 heap에 있는 모든 개체를 검사하며 끊기거나 느려질 수 있다.
  • Memory Profiler를 이용하여 fragmentation 또는 메모리 누수를 확인한다.
  • GC의 영향을 줄인다.
    • JSON 또는 XML을 통한 문자열 기반 파싱을 피한다. ScriptableObjects 또는 MessagePack과 같은 형태에 데이터를 저장한다.
    • 문자열을 비교하는 GameObject.tag 대신 GameObject.CompareTag를 사용한다.
    • Coroutines에서 yield 자체는 GC를 발생시키지 않지만, WaitForSeconds는 발생시킨다. yield 라인을 생성하는 것 보다 WaitForSeconds를 캐싱해서 사용한다.
    • 퍼포먼스 이슈를 위해 LINQ와 Regular Expressions를 피한다.
  • Use incremental GC 기능을 사용한다. 이전 글에 해당 기능에 대한 설명을 작성했다.
 

[Unity] 그래픽스 최적화 - Graphics Jobs, Use incremental GC 기능

Graphics Jobs This enables rendering code to be split and run in parallel on multiple cores on multi core machines. This is stored as a platform specific property and acts upon the currently active build target. 워크로드를 보다 효과적으로 균

lightbakery.tistory.com

 

 


 

 

Programming and code architecture

  • Update, LateUpdate, FixedUpdate와 같은 매 프레임 연산되는 코드는 최대한 줄인다.
  • Awake, OnEnable, Start에는 무거운 로직을 넣지 않는다.
  • MonoBehaviours는 비어있어도 리소스를 먹기 때문에 비어있는 Update와 LateUpdate는 지운다. 테스트를 위해서 사용한다면 #if UNITY_DEITOR / #endif 전처리기 지시어를 사용한다. 오버헤드가 발생하지 않는다.
#if UNITY_EDITOR
void Update()
{
}
#endif
  • 문자열 파라미터 대신 해시값을 사용한다.
  • 런타임 중에 AddComponent 사용을 피한다. 컴포넌트가 런타임 중에 추가되면 중복되거나 다른 필요한 컴포넌트가 있는 지 확인하는 과정에서 코스트가 소모된다.
  • GameObject.Find, GameObject.GetComponent, Camera.main은 Update 메서드에서 호출하지 말고 Start에서 호출한 후 캐시한다.
void Update()
{
    Renderer myRenderer = GetComponent<Renderer>();
    ExampleFunction(myRenderer);
}
private Renderer myRenderer;

void Start()
{
    myRenderer = GetComponent<Renderer>();
}

void Update()
{
    ExampleFunction(myRenderer);
}
  • Instantiate과 Destory에 GC가 돌아가기 때문에 Object Pool을 사용한다.
  • 바뀌지 않을 값이나 세팅을 MonoBehaviour를 사용하지 않고 ScriptableObject를 사용하여 저장한다. 이후에 MonoBehaviour에서 참조한다.
728x90
반응형