본문 바로가기

유니티/기타

[Unity] 가비지 컬렉션, 베스트 프래틱스

반응형

이 글은 unity에서의 가비지 컬렉션에 대해 알아보기 위해 정리한 글입니다. 초반부에는 유니티 공식문서를 기반으로 내용을 정리하고, 후반에는 참고한 글들과 개인적 경험을 바탕으로 글을 작성하겠습니다.

 

 

공식문서(매뉴얼) 정리 내용


Unity는 응용 프로그램에서 메모리를 처리하기 위해 세 가지 메모리 관리 레이어를 사용합니다

- 관리되는 메모리: 관리되는 힙과 가비지 컬렉터를 사용하여 자동으로 메모리를 할당하는 제어되는 메모리 레이어

- 관리되지 않는 메모리: 가비지 컬렉터를 사용하지 않는 메모리

- 네이티브 메모리: Unity에서 엔진을 구동하는 데 사용하는 c++ 메모리.

 

가비지 컬렉터는 애플리케이션에서 메모리를 관리하는 가장 쉬운 방법이지만, 메모리 해제/할당 타이밍을 예측할 수 없기 때문에 불안정한 성능 문제가 생길 수 있습니다. 이러한 문제를 해결하려면 '관리되지 않는 메모리 레이어'를 사용하면 됩니다. 관리되지 않는 메모리 레이어는 NativeArray등 Unity.Collections 네임스페이스에 있는 자료구조등을 통해 접근할 수 있습니다.

 

관리되는 메모리

 관리되는 메모리는 레퍼런스가 없는 메모리를 자동으로 해제하는 가비지 컬렉터와 유효하지 않은 메모리에 액세스할 수 없게 해주는 보호 역할을 합니다.

 

유니티는 오브젝트가 할당되었으나 힙에 이를 수용할 만한 크기의 연속된 공간이 없는 경우 두 개의 작업을 실행합니다.

1. 가비지 컬렉터(GC)가 실행되지 않은 경우 이를 실행시킵니다.

2. GC가 실행된 이후에도 메모리 공간을 수용할 수 있는 연속된 공간이 없는 경우 힙을 확장시킵니다. 힙이 확장되는 구체적인 크기는 플랫폼에 따라 다르지만, 대부분 2배만큼 확장됩니다.

 

가비지 컬렉터 개요

 Unity는 스크립트가 관리되는 힙에 할당하려고 하지만 할당을 수용할 힙 메모리가 충분하지 않으면 가비지 컬렉터를 실행시킵니다. GC가 실행되면 힙의 모든 오브젝트를 검사하고 더 이상 레퍼런스가 없는 오브젝트를 삭제하도록 표시합니다. 그 이후 Unity는 레퍼런스가 없는 오브젝트를 삭제하여 메모리를 확보합니다.

 

- 점진적 가비지 컬렉션: 기본적으로 활성화되어 있으며, 가비지 컬렉션 프로세스를 여러 프레임에 분산시킵니다.

- 자동 가비지 컬렉션 비활성화: GarbageCollector.GCMode API를 이용하여 GC실행 시기를 완전히 제어할 수 있습니다.

 

점진적 가비지 컬렉션

Unity의 가비지 컬렉터는 점진적 모드에서 Boehm-Demers-Weiser 가비지 컬렉터를 사용합니다.

 

A garbage collector for C and C++

A garbage collector for C and C++ [ This is an updated version of the page formerly at http://www.hpl.hp.com/personal/Hans_Boehm/gc, and before that at http://reality.sgi.com/boehm/gc.html and before that at ftp://parcftp.xerox.com/pub/gc/gc.html. ] The Bo

www.hboehm.info

 

즉, GC는 힙의 오브젝트를 처리하기 위해 메인 CPU스레드를 완전중지(Stop-the-world)하는 대신 작업량을 여러 프레임에 걸쳐 분할합니다.(아래 문서 참고) 이는 GC를 과정을 빠르게 만들지는 않지만, GC 관련 성능 스파이크가 줄어들게 됩니다. 만약 점진적 모드를 사용하지 않으면 stop-the-world 방식의 GC를 사용하게 됩니다.

 

Tracing garbage collection - Wikipedia

From Wikipedia, the free encyclopedia In computer programming, tracing garbage collection is a form of automatic memory management that consists of determining which objects should be deallocated ("garbage collected") by tracing which objects are reachable

en.wikipedia.org

 

참고: WebGL에서는 점진적 GC를 지원하지 않습니다.

 

 

애플리케이션에서 VSync또는 Application.targetFrameRate를 사용하는 경우, Unity는 사용 가능한 남은 프레임 시간을 기준으로 GC에 할당하는 시간을 조정합니다. Unity는 특정 프레임이 끝날 때 남은 대기 시간을 점진적으로 GC에 사용합니다. 점진적 가비지 컬렉션 동작을 더욱 정밀하게 제어하기 위해 Scripting.GarbageCollector 클래스를 사용할 수도 있습니다.

 

GC 베스트 프랙틱스 (공식문서버전)

유니티 공식 매뉴얼에서 설명하고 있는 Unity작업중 GC를 줄일 수 있는 방법들입니다. 어찌보면 뻔한(?)내용들이라 생략하겠습니다. 자세한 내용은 아래 문서 참고 바랍니다.

 

- 임시 할당

- 재사용 가능 오브젝트 풀

- 반복된 스트링 배열

- 배열 값 반환 메서드

- 컬렉션과 배열 재사용

- 클로저 및 익명 메서드

- 박싱

- 배열 기반 Unity API

- 빈 배열 재사용

 

 

가비지 컬렉션 베스트 프랙티스 - Unity 매뉴얼

가비지 컬렉션은 자동으로 작동하지만 프로세스하는 데 CPU 시간이 상당히 많이 소요됩니다.

docs.unity3d.com

 

 

메뉴얼 외 다른 글 참고 내용


 분명 C#의 GC에 대해 공부했을 때 LOH, SOH, 그리고 세대 별 GC에 대해서 배웠었고 이를 면접에서 당당하게 말하고 다녔었는데, 공식 메뉴얼에서는 해당 내용을 찾아볼 수 없었습니다. 그러던 중 'Unity GC는 그딴거 없다'라는 사실을 깨닫게 되었습니다. 아래 글을 정리하자면 'Unity는 모종의 이유로 고전적인 GC를 사용하고 있고, 개선은 하려고 하고 있지만 아직 되진 않았다'가 될 것 같습니다. (관련 내용찾아보고있는데 2023년 현재도 적용되지 않은것 같습니다) (진짜 충격이다 유니티!)

 

- 세대구분 없음

- SOH, LOH 구분 없음

- 메모리 재정렬 없음

 

 그런데 무서웠던(?)점은 유니티 가비지 컬렉터 관련된 내용을 정리한 글들에서 유니티도 닷넷과 같은 방식으로 GC를 수행한다고 적혀있는 글들이 많았던 것이다. 이를 면접에서 당당히 말하고 다녀서 떨어진 것인가. 제 블로그 글들을 보신 분들은 현재 버전에서 닷넷과 유니티 GC의 차이점을 알고 가셨으면 좋겠습니다.

 

 

Unity's garbage collector - Why non-generational and non-compacting?

I've just read in Unity's docs that Unity’s garbage collection – which uses the Boehm GC algorithm – is non-generational and non-compacting. “Non-generational” means that the GC must sweep throu...

stackoverflow.com

 

 

 

Native Heap

 공식문서에서 그냥 엔진 내부 코어에서 관리되는 '네이티브 메모리' 시스템이 있고, 프로젝트, 에셋, 그래픽스 API 등등이 이 메모리에서 관리된다고 적혀있었는데, 'Texture, Mesh'와 같은 Asset들도 해당 메모리에서 관리되는듯 하다. 뭔가 Texture에셋이 쌓이면 메모리가 자동으로 해제가 안되는 현상이 있어서 수동으로 해제를 해줬었는데, 관리되는 메모리 레이어가 그랬던 것으로 생각하면 될것같다. 해당 메모리는 Scene전환 발생 시 사용하지 않으면 메모리를 해제하는 동작을 수행한다.

 

GC 베스트 프랙틱스2(Cysharp숭배)

유니티에서 쓸모없는 메모리 할당을 피하려면 어떻게 해야 하는게.

대부분 Cysharp의 패키지를 활용하자로 귀결됬다.

그중에서도 가장 많이(특히 내 프로젝트에서는 필수로 사용하는)패키지 2가지를 소개하자면 다음과 같다.

 

Zstring

이름부터 Zero Allocation StringBuilder이다.

많은 수의 파라메터를 조합한 텍스트를 만들어야 하는 경우 꼭 사용하는 편이다.

 

GitHub - Cysharp/ZString: Zero Allocation StringBuilder for .NET and Unity.

Zero Allocation StringBuilder for .NET and Unity. Contribute to Cysharp/ZString development by creating an account on GitHub.

github.com

 

UniTask

UniTask는 Zero Allocation기능을 제공하여 메모리 할당을 최소화한다. 코루틴은 기본적으로 메모리 할당을 필요로 하며 이는 GC 오버헤드를 초래한다.

 

코루틴의 힙 할당

- 코루틴을 관리하기 위해 인스턴스를 생성해야만 함

- yield 구문에 전달하는 값이 할당을 발생시킴(값의 박싱 또는 WaitForSeconds 오브젝트 할당)

 

 

 

 


참고

https://everyday-devup.tistory.com/14

https://docs.unity3d.com/kr/2021.3/Manual/performance-garbage-collector.html

https://docs.unity3d.com/kr/2021.3/Manual/performance-garbage-collection-best-practices.html

https://ronniej.sfuhost.com/optimizing-garbage-collection-in-unity-games-5/

 

 

 

반응형

'유니티 > 기타' 카테고리의 다른 글

[RenderTexture] 유니티 렌더텍스처 기본  (0) 2022.04.14