티스토리 뷰

반응형

[스크립트 최적화]


# 유니티의 핵심 기능은 모두 C++로 제작되어 있다.


# 리스트나 ArrayList 객체를 사용하는 요령

length = array.Length;

for (i=0;i<length;i++)

{

}


for (i=0;i<array.Length;i++)

{

}


위 두 코드의 차이점이 있을까? 있다면 어느 방법이 더 좋을지 알 수 있습니다.


# 예) Transform.position 에서 Transform은 C# 속성, Position은 C++ 영역


# 유니티 객체들을 멤버 변수에 저장해서 캐싱하여 사용하는 것이 좋다.


private Transform _tr;

void Awake()

{

_tr = GetComponent<Transform>();

}


# FindObject 계열 함수들은 매우 느리다. (미리 찾아서 캐싱)

 - 예를 들어 Find 라는 검색이 붙은 것들은 웬만하면 지속적으로 사용하지 않는 것이 좋습니다. Find는 프로젝트 안의 모든 오브젝트를 순환하며 그 안의 클래스의 스트링을 비교하기 때문입니다.


# Instanitate 와 Destory 함수를 이용한 프리팹의 생성/해제는 비용이 크다

 - 활성화/비활성화를 활용한 오브젝트 풀을 사용하는 것이 좋습니다.


# Update 함수보다는 Coroutine을 활용한다.


단 반드시 사용을 사용을 해야 한다면

void Update()

{

if (Time.frameCount % 6 == 0) DoSomething();

}


void Update()

{

InvokeRepeating("DoSomeThing", 0.5f, 1.0f); 

}


위 코드중에서 어느 코드가 좋을지 생각하면 좋을 것입니다. 하지만 위 두가지가 사용 차이점이 있습니다.


# 박싱과 언박싱은 부하가 큰 작업이다.

 

# 나눗셈보다는 곱셈이 몇십 배 빠르다.

 - 나눗셈은 곱셈보다 연산 속도가 월등히 느립니다. 100 / 10 이런 식이 아닌 100 * 0.1을 사용


# magnitude 보다는 sqrMagnitude를 사용해서 비교한다. (제곱근 계산 x)

 - Unity 공식 문서에서 쓰여있습니다.


# 삼각함수의 값은 상수로 저장하고 사용하는 것이 좋다.


# 문자열은 readonly 혹은 const 키워드를 사용해 가비지 컬렉션으로부터 벗어나도록 한다.


# SendMessage 와 같은 function 의 사용은 피한다. 직접 function을 사용하는 방법이 훨씬 빠르고 사용하는 것을 권장한다.





[만흉의 원인 : 가비지 컬렉터]


가비지 컬렉터(GC)는 언제 일어날지 모릅니다.


# Mono의 동적 메모리 관리 때문에 메모리 해제를 위해 GC가 자동 호출된다.

 

# GC는 언제 일어날지 모른다.


# GC가 일어나면 게임이 멈추는 현상이 발생하게 된다.


# 동적 메모리 해제가 가능한 일어나지 않도록 하는 것이 GC 관리의 핵심


- 우리가 쓰고 있는 MonoBehavior는 메모리 관리에 GC가 자동 호출되도록 설계되어 있습니다. 이 GC가 프로그래머의 입장에서 좋을 수도 있고 그렇지 않을 때도 있습니다. GC가 실행되는 동안 많은 양을 처리하게 되면 렉 현상을 겪게되며 그렇지 않기 위해서는 게임을 만들 때 GC를 고려하여 만들어야합니다. 가비지 컬렉터의 할 일을 줄여주기 위한 방법에 대해 알아보겠습니다.


[1] 무엇이든 동적 생성 및 해제는 굉장히 비용이 큰 작업입니다.

 위에 언급된 바가 있는 오브젝트 풀링 기법을 사용해 메모리를 관리하는 것이 좋습니다.


[2] 오브젝트가 해제되면 다음 과정으로는 GC가 동작되어 렉이 걸릴 수 밖에 없습니다.

 즉 오브젝트를 만들어둔 후 활성화 또는 비활성화를 이용해 사용하도록 하는 것이 좋습니다.


[3] 문자열 병합은 StringBuilder의 Append를 사용하면 좋습니다.

 왜냐하면 string + string은 임시 문자열을 뱉기 때문에 가비지 컬렉션이 일어나는 환경을 제공하기 때문입니다.


[4] foreach 대신에 for를 이용하도록 합니다.

 foreach는 한번 돌리면 24byte의 가비지 메모리를 생성시키게 되며 수많이 돌면 더 많은 메모리를 생성시키게 되므로 for 문을 이용하도록 하는 편이 좋습니다.


[5] 태그 비교에서는 CompareTag()를 사용하도록 합니다.

 객체의 tag 프로퍼티를 호출하는 것은 추가 메모리를 할당하며 복사를 하게됩니다.


[6] 모든 비교문에서 .equals()를 사용하도록 합니다.

 "==" 구문으로 사용하게되면 임시적인 메모리가 남게 되며 가비지 컬렉션이 할 일이 늘게 됩니다.


[7] 데이터 타입은 Class 대신 Struct를 사용하여 만들어 주면 메모리 관리가 된다.

 구조체는 메모리 관리를 Stack에서 하므로 GC에 들어가지 않게 됩니다.


[8] 즉시 해제시에는 Dispose를 수동으로 호출하게 되면 즉시 클린업됩니다.


[9] 임시 객체를 만들어내는 API를 조심해야합니다.

 GetComponents<T>, Mesh, Vertices, Camera.allCameras 등등..


[10] 객체의 변경 사항에 대해 캐싱합니다.

 객체의 이동과 변형에 대한 처리를 캐싱해서 매 프레임당 한번만 처리합니다.


[11] 컴포넌트 참조를 캐싱한다.

 GetComponent()는 한번만 호출하며 객체를 캐싱해서 사용한다.


[12] 콜백 함수중 쓰지 않는 함수는 제거합니다.

 Start(), Update(), OnDestroy() 등.. 비어있어도 성능에 영향을 끼치므로 지워주도록 합니다.

728x90
반응형
댓글