Unity 내일배움캠프 TIL 1013 | 스크립트 최적화

cheeseonrose·2023년 10월 13일
0

Unity 내일배움캠프

목록 보기
55/89
post-thumbnail

💡 Unity Documentation - 스크립트 최적화

🐱 메모리 할당

  • Unity에서 작성하는 스크립트는 자동 메모리 관리를 사용
  • Unity가 알지 못하는 오브젝트(예: 어느 것으로부터도 상속받지 않는 클래스의 인스턴스)를 생성한 다음 오브젝트를 레퍼런스하는 변수를 null로 설정하면, 해당 스크립트와 Unity에 관한 오브젝트를 잃어버리게 됨
    -> 해당 오브젝트에 접근하거나 다시 볼 수 는 없지만 메모리에 남아있는 상태
    -> 시간이 지나면 가비지 컬렉터가 메모리의 각 블록에 대한 레퍼런스의 수를 내부적으로 계속 추적하다가, 메모리에 남아 있지만 어디서도 레퍼런스 되지 않는 오브젝트를 제거
    -> 이는 스크립팅 언어가 C++보다 느린 이유 중 하나

🐶 메모리 할당을 피하는 방법

  • 어떤 오브젝트가 생성될 때마다 메모리가 할당됨

  • GUI는 느리므로 성능이 문제가 될 때에는 사용 X

  • Debug.Log("po" + "tato"); 는 오브젝트를 생성함
    -> 많은 양의 문자열을 다룰 때는 System.String.Empty 를 사용

  • ClassStruct의 차이

    • Class : 오브젝트이면서 레퍼런스로서 작동
    • 아래 코드에서 MyFood는 힙에 할당된 원본 potato를 가리키는 레퍼런스를 넘겨받게 됨
      -> MyFood에서 potato를 변경시키면 potato가 레퍼런스 되는 모든 곳에서 변경된 내용 확인 가능
      Potato potato = new Potato();
      MyFood(potato);
    • 만약 Potato가 구조체라면
    • MyFood는 potato의 복사본을 넘겨받게 됨 -> 가비지 컬렉션 대상 X
    • 장시간 유지되어야 하는 오브젝트는 클래스
      단시간만 사용할 오브젝트는 구조체
    • 가장 대표적인 구조체 예시 : Vector3

🐰 오브젝트 풀링

  • 오브젝트 풀링을 통해 메모리 할당을 더 간단하게 할 수 있고, 동적 메모리 할당 오버헤드와 가비지 컬렉션을 없앨 수 있게 된다.

  • 오브젝트 풀링이 더 빠른 이유

    • 인스턴스화 및 제거를 여러 차례 사용하면 가비지 컬렉터가 해야 할 일이 많아짐
      -> 아무 일도 진행되지 않을 때 가비지 컬렉터를 수동으로 작동
      or 가비지 컬렉터를 매우 자주 작동시켜서 사용하지 않는 메모리가 대량으로 쌓이지 않도록 방지
  • 오브젝트 풀링이 느린 이유

    • 풀을 생성하면 다른 목적으로 사용할 가용 힙 메모리의 양이 줄어든다.
      -> 현재 막 생성한 풀 외에도 메모리를 계속 할당한다면, 가비지 컬렉션이 더욱 자주 실행될 수 있음
    • 가비지 컬렉션에 걸리는 시간은 살아있는 오브젝트의 수에 비례하여 증가하기 때문에 매번 더 느려질 수 있다.

🐥 애니메이션 스프라이트 파티클 시스템

  • 비슷한 방식으로 움직이며 플레이어가 주의 깊게 살펴볼 일이 절대로 없는 오브젝트를 여러 개 표시하기 위해 파티클 시스템을 사용하여 순식간에 대량의 오브젝트를 렌더링하게 된다.
    -> 스프라이트 패커 무료 에디터 확장 프로그램을 사용

  • 스프라이트 패커는 오브젝트의 프레임을 텍스처에 렌더링하며, 이를 파티클 시스템에서 애니메이션 스프라이트 시트로 사용할 수 있다.


🐧 수천 개의 오브젝트를 관리하는 기법

  • 불필요한 검색 대신 캐시 레퍼런스 사용

    void Update()
    {
    	transform.LookAt(GameObject.FindWithTag("Player").transform);
      	transform.position += transform.forward * speed * Time.deltaTime;
    }
    • GameObject.FindWithTag는 최적화 되었지만, 많은 수의 인스턴스를 실행하는 스크립트에서는 조금 느려질 수 있다.
    • 아래와 같이 개선 가능
    private Transform myTransform;
    private Transform playerTransform;
    
    void Start() 
    {
    	myTransform = transform;
      	playerTransform = GameObject.FindWithTag("Player").transform;
    }
    
    void Update()
    {
    	myTransform.LookAt(playerTransform);
      myTransform.position += myTransform.forward * speed * Time.deltaTime;
    }
  • 비용이 큰 수학 함수 최소화

    • Mathf.Sin, Mathf.Pow, 나눗셈, 제곱근 등의 연산은 곱셈 연산 대비 100배 정도 시간을 소모한다.
    • 벡터를 정규화할 때, 동일한 벡터를 반복해서 정규화하는 대신 한 번만 정규화하고 그 결과를 캐싱하는 방법을 고려할 수 있다.
      -> 벡터의 길이도 사용하고 정규화도 해야 한다면 .normalized 프로퍼티를 사용하는 것보다 벡터에 길이의 역을 곱해서 정규화 벡터를 얻는 것이 더 빠름
  • Physics.Raycast()처럼 비용이 큰 연산은 지양

    • FixedUpdate는 물리 업데이트를 나타내며, 프레임 업데이트보다 더 자주 일어난다.
    • 비용이 크게 드는 처리를 할 때는 처리를 덜 하는 방향으로 최적화하고, 결과를 캐싱하는 것이 좋다.
  • 콜스택 오버헤드 최소화

    • 함수를 호출하는 것만으로도 약간의 오버헤드가 발생한다.
      x = Mathf.Abs(x) 보다는
      x = (x > 0 ? x : -x) 와 같이 처리



끗!

0개의 댓글