본문 바로가기

유니티/프로젝트 최적화

[Unity] 스크립팅 최적화(1) - 반복되는 연산 줄이기

반응형

반복되는 구간 줄이기?

유니티에서 컴포넌트 스크립팅을 하다 보면 필연적으로 반복되는 구간이 나오게 된다.

예를 들어, Update이벤트에서 사용되는 함수가 대표적인 경우이다.

그중 몇 개는 매프레임마다 반드시 실행되어야 하지만 최초 1회 혹은 특정 순간만 필요한 경우일 때도 많다.

후자의 상황인 경우 우리는 불필요한 연산을 줄이도록 스크립팅을 해야 한다.


반복으로부터 발생하는 비용을 없앨 수 있을까?

많은 방법이 있지만 대표적으로 다음과 같은 방법을 사용할 수 있다.


컴포넌트 캐싱

캐싱은 스크립트 최적화의 기본이 되는 아주 중요한 개념이다. 유니티에서는 특별히 "GetComponent<T>()"함수와 자주 사용되는데, 이는 GetComponent가 CPU 오버헤드를 일으킬 수 있는 반면, 캐싱이 이를 해결하기 때문이다.

 

다음 예문을 살펴보자.

void Update()
{
	if (GetComponent<Player>().health <= 0) 
        {
            GetComponent<RigidBody>().enabled = false;
            collider.enabled = false;
            anim.SetTrigger("Death");
        }
}

 

위 Update에서는 매 프레임마다 Player와 RigidBody의 컴포넌트를 가져오고 있다.

 

이렇게 자주 쓰이는 문장이라면 매번 cpu에게 Player와 Rigidbody를 찾으라고 고생시킬 필요가 있을까?

우리는 별도의 전역변수를 사용해서 그 변수에 1회만 참조값을 넣어두고 해당 변수를 계속 사용하는 형태로 변경할 수 있다.

이렇게 자주 쓰이는 변수에 참조값을 담아서 사용하는 것을 캐싱이라고 한다.

 

위의 문장은 아래와 같이 바꿀 수 있다.

private Player player;
private RigidBody rb;

void Start()
{
	player = GetComponent<Player>();
	rb = GetComponent<RigidBody>();
}

void Update()
{
	if (player.health <= 0) 
        {
            rb.enabled = false;
            collider.enabled = false;
            anim.SetTrigger("Death");
        }
}

이제 cpu가 변수를 만나면 메모리의 위치를 알고 있기 때문에 이전과 같은 문제는 발생하지 않는다.

 

그런데 이런 궁금증이 생길 수 있다.

 

  "캐싱을 통해 GetComponent의 문제점을 해결할 수 있다면, 참조가 필요한 형태의 모든 컴포넌트들을 다 캐싱해 두고 사용하면 되지 않을까?"

 

물론 GetComponent가 비싼 비용이고 캐싱의 이점이 뛰어난 것은 맞으나, 모든 것이 그렇듯 캐싱의 단점이 전혀 없는 것은 아니다.

캐싱을 하기 위해서는 별도의 변수를 선언해 메모리공간을 확보해야 한다.

다만 이 값이 매우 작아서(32bit나 64bit의 공간) 한두 번의 사용으로는 티도 나지 않는다.

그러나 메모리 병목현상(Memory bottleneck)과 같은 경우를 경계해야 하는 것은 분명하다!

 

Update와 같이 자주 반복되는 함수에서 어떠한 컴포넌트 참조를 해야 한다거나 박싱 및 언박싱이 이루어지는 경우에는 습관적으로 캐싱을 하도록 하자.


결과값 공유

다음과 같은 상황이 있다고 가정하자.

씬에 100개의 캐릭터가 랜덤한 위치에 생성되고 그중 1개는 플레이어(유저), 5개는 핵심 적 캐릭터, 나머지 94개는 일반 배경 캐릭터이다.

이때 유저를 제외한 나머지 99개의 캐릭터가 유저의 위치 정보를 공유해야 한다면, 처음 스크립트가 시작될 때 99개의 캐릭터 각각이 유저의 위치를 찾는 과정을 수행해야 할까?

당연히 그렇지 않다. 이 때는 결과를 하나의 스크립트에서만 찾고 필요한 컴포넌트가 그 값을 공유하면 된다.

 

또한 수많은 데이터 묶음에서 특정 값을 찾는 과정이나 복잡한 수학 계산, 레이캐스팅 등이 모두 이에 해당된다.

 

어떤 스크립트에서 이러한 프로세스를 처리하고 나서 편하게 공유하려면 어떻게 해야 할까?

우리는 이러한 처리를 싱글톤 패턴이나 옵저버 패턴 등을 사용해 쉽게 해결할 수 있다.

 

 

반응형