힙 메모리 영역
프로그램을 만들 때 힙 메모리 영역은 프로그래머가 항상 신경 써야 되는 중요한 메모리 영역이다.
유니티에서 힙 변수가 생성될 때 여유 메모리가 충분하지 않다면 가비지 컬렉션작업을 수행한다.
하지만 가비지 컬렉션 작업은 꽤나 무거운 작업이기 때문에 이 순간 프레임 드랍이 발생한다.
이를 개선하기 위해 최근에는 Inscremental GC 기능이 업데이트 되긴하였지만,
그래도 가비지 컬렉션의 대상이 되는 힙 할당을 최대한 만들지 않는 것이 좋다.
1. 자주 사용되는 참조 변수는 캐싱하기
다음의 코드는 함수를 호출할 때마다 새로운 힙 메모리 영역에 할당하게 되어 가비지가 발생한다.
public void MyMethod()
{
Button btn = GetComponent<Button>(); // 함수 호출시 마다 힙 메모리를 할당한다.
SomeMethod(btn);
}
다음과 같이 참조를 멤버 변수로 선언하여 가비지를 줄일 수 있다.
private Button btn;
void Start()
{
btn = GetComponent<Button>();
}
public void MyMethod()
{
SomeMethod(btn);
}
2. 컬렉션을 새로 만들 때 발생하는 가비지
다음의 코드는 매 프레임 새 컬렉션을 생성하고 있다.
public void Update()
{
List<int> myList = new List<int>();
SomeMethod(myList);
}
컬렉션을 Clear()로 내용을 비워서 사용하면 가비지를 줄일 수 있다.
private List<int> myList = new List<int>();
public void Update()
{
myList.Clear();
SomeMethod(myList);
}
3. 문자열 연결 시 발생하는 가비지
문자열은 값처럼 보이지만 사실 참조 유형이다. 이를 연결하는+ 연산자는 대표적인 가비지를 생산하는 주범이다.
아래의 코드에서는 기존의 문자열이 존재하는 메모리 공간에 연결시킨 것이라 착각할 수 있다.
하지만 실제로는 새 문자열을 만들고 이전 문자열을 가비지로 버린다.
string name = "Mark";
string str = "My Name : ";
str += name;
문자열 여러 개를 연결할 때는 가급적 stringBuilder 클래스를 사용하도록 하자.
4. Unity 함수 호출에서 발생하는 가비지
직접 작성하지 않은 코드는 가비지가 발생할 수 있다는 점을 염두에 두도록 하자.
배열을 반환하는 Unity 함수에 액세스 할 때마다 새 배열이 생성되어 반환된 값으로 전달된다.
다음의 코드는 반복문 안에서 매번 Mesh.normals를 호출할 때마다 배열이 생성된다.
public void MyMethod()
{
for (int i = 0; i < myMesh.normals.Length; i++)
{
Vector3 normal = myMesh.normals[i];
}
}
다음과 같이 캐싱을 해서 가비지를 방지할 수 있다.
public void MyMethod()
{
Vector3[] normals = myMesh.normals;
for (int i = 0; i < normals.Length; i++)
{
Vector3 normal = normals[i];
}
}
GameObject.tag이나 GameObject.name 접근 시에도 매번 문자열을 생성해서 반환한다.
void OnTriggerEnter(Collider other)
{
if(other.gameObject.tag == "Player")
{
//...
}
}
태그 비교는 GameObject.CompareTag()를 사용하면 힙 할당을 하지 않는다.
string playerTag = "Player";
void OnTriggerEnter(Collider other)
{
if(other.gameObject.CompareTag(playerTag))
{
//...
}
}
이외에도 힙 할당을 발생하는 유니티 함수들과 힙 할당을 하지않은 대체용 함수들이 존재한다.
Input.GetTouch()와 Input.touchCount는 힙 할당을 일으키니 Input.touches를.
Physics.SphereCastAll() 대신 Physics.SphereCastNonAlloc() 를 사용하도록 하자.
5. 코루틴에서 발생하는 가비지
yield 자체는 힙 할당을 하지 않지만 전달하는 값은 박싱이 되기 때문에 힙 할당이 발생할 수 있다.
yield return 0; // 0인 int 값 변수가 boxing되기 때문에 가비지를 발생시킨다.
new 를 통해 생성하는 객체는 가비지를 만든다.
While(true)
{
yield return new WaitForSeconds(1f); // 매번 새로운 객체가 생성된다.
}
WaitForSecond 또한 객체이기 때문에 멤버 변수나 지역변수로 캐싱할 수 있다.
WaitForSeconds delay = new WaitForSeconds(1f);
While(true)
{
yield return delay;
}
6. Foreach 루프 (유니티 5.5 이하 버전)
유니티 5.5 이하 버전에서는 foreach를 실행하면 루프가 종료될 때마다 박싱이 일어났지만,
최근 버전에서는 수정되었다.
'🌍 Unity > 최적화' 카테고리의 다른 글
유니티 최적화 : 스프라이트 아트라스 (Sprite Atlas) (1) | 2021.07.18 |
---|---|
유니티 최적화 : 2D 스프라이트 최적화 (0) | 2021.07.18 |
유니티 최적화 : 스크립트 최적화 (0) | 2021.04.27 |
유니티 최적화 : parameter ID의 Hash value 캐싱 (0) | 2020.08.27 |
UI Overlay 오브젝트가 배칭이 안되는경우 확인할 것. (0) | 2020.07.31 |