가비지 컬랙션(GC)
메모리 관리를 위해 사용되며, 더 이상 사용되지 않는 메모리를 해체하여 성능을 최적화한다.
유니티에서 GC는 Mono런타임에 의해 관리되며, C# 스크립트에서 사용되는 객체들의 메모리를 관리한다.
가비지 컬랙션 발생 순서
1. 메모리 할당
- 새로운 객체나 데이터 구조가 메모리에 할당된다.
2. 참조 계수 증가
- 해당 객체애 대한 참조가 증가한다.
- 참조 계수 : 객체가 몇번 참조되고 있는지를 나타내는 카운트이다. 객체가 최초로 생성되면 참조 계수가 1이다.
참조 계수가 0이 되면 해당 객체는 더이상 사용되지 않은 것으로 판단되고, 메모리에서 해제될 수 있다.
3. 사용 및 참조 해제
- 객체가 사용되고 필요 없어질 때, 해당 객체 대한 참조를 해제한다.
4. 가바지 컬렉션 트리거
5. 표시
- 가비지 컬렉션이 필요한 메모리 블록을 식별하는 과정이다. 이 과정에서 어떤 객체가 여전히 유효한지 검사한다.
6. 수거
- 표시되지 않거나 참조가0인 객체를 메모리에서 해제한다.
7. 세대 이동
- 가비지 컬렉션에서 남아 있는 객체가 다음 세대로 이동한다.
가비지 컬렉션 발생 시 단점
1. 일시적인 중단
- 가비지 컬렉션 실행 중에 프로그램이 일시적으로 중단될 수 있음
2. CPU 소모
- 가비지 컬렉션이 실행될 때 CPU자원을 소모하기 때문에 빈번한 가비지 컬렉션은 성능에 영향을 끼칠 수 있다.
3. 메모리 사용 지연
- 가비지 컬렉션이 진행되는 동안에 메모리를 해제하는 시간이 오래 걸릴 수 있어 메모리 사용량이 높게 측정될 수 있음
4. 메모리 누수
- 부정확하게 사용할 경우 메모리 누수가 발생할 수 있으며, 참조를 적절하게 관리하지 못하면 객체 해제를 못할 수도 있다.
가비지 컬렉션 빈도를 줄이는 법
1. 객체 풀링 사용
- 빈번한 객체 생성 과 제거를 피하기 위해 객체 폴링을 사용한다.
2. 로컬 변수 사용
- 로컬 변수를 활용하여 메서드 내에서 사용되는 객체의 범위를 최소화 한다.
3. 불필요한 객체 생성 자제
4. 약한 참조 활용
- 약한 참조를 하여 컬렉션의 대상이되는 객체의 수를 줄인다.
5. 명시적인 가비지 컬렉션 호출 최소화
가비지 컬렉션이 많이 발생하는 예제 코드
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Test : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
// 매 프레임마다 새로운 벡터를 생성하고 사용
Vector3 newPosition = new Vector3(1.0f, 2.0f, 3.0f);
transform.position = newPosition;
string result = "Hello " + "World";
Debug.Log(result);
// 리스트에 계속해서 새로운 객체를 추가하고 사용
for (int i = 0; i < 100; i++)
{
var tempList = new System.Collections.Generic.List<int>();
tempList.Add(i);
// tempList를 사용하지 않고 버림, 그러나 가비지 컬렉션의 대상이 됨
}
}
}
해당 코드에서 가비지콜렉션 빈도를 줄인 코드
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Test : MonoBehaviour
{
private Vector3 newPosition;
// Start is called before the first frame update
void Start()
{
newPosition = new Vector3(); // 초기화
}
// Update is called once per frame
void Update()
{
// 매 프레임마다 새로운 벡터를 재사용
newPosition.Set(1.0f, 2.0f, 3.0f);
transform.position = newPosition;
// 문자열 연산을 사용하지 않고 이미 존재하는 문자열을 출력
Debug.Log("Hello World");
// 리스트를 재활용하고 불필요한 객체 생성을 방지
var tempList = new System.Collections.Generic.List<int>();
tempList.Clear(); // 리스트를 초기화하고 재활용
for (int i = 0; i < 100; i++)
{
tempList.Add(i);
// tempList를 사용하지 않고 버리지 않음
}
}
}