성능에 조금이라도 관심 있는 사람은 GC에 대하여 들어본적이 있을 것이다.

그래서 유니티의 GC에 대해 공부하다보면, 발견할 수 있는 점이 .NET의 GC와 Unity의 GC가 다르다는 점이다.

 

필자는 유니티의 GC를 언뜻 듣고, .NET의 GC를 공부하고 나서,

당연히 유니티도 C#을 쓰니 같은 GC겠거니 했는데, 그게 아니었다.

 

이번 글에선 왜 그런지를 알아보려고 한다.

 

.NET Framework Garbage Collector

일단, 각 GC가 어떻게 동작하는지 심플하게 설명해보자.

.NET Framework의 GC는 세월이 흐르면서 여러 방법으로 업그레이드 되어 왔다.

 

기본적으로 .NET의 GC는 세대(Generation) 방식을 사용한다.

할당된 메모리별로 0~2세대까지 세대를 부여하여,

통계적으로 (자기네들이 생각하기에) 최적의 타이밍에 필요한 메모리를 해제할 수 있도록 관리한다.

 

그리고 힙영역은 SOH(Small Object Heap)과 LOH(Large Object Heap)으로 구분하여,

큰 메모리를 할당하고 해제할 때의 부담을 줄도록 만들었다.

 

SOH에는 작은 메모리들이 할당되고, GC가 일어날 때, 정리된 세대의 메모리의 재정렬이 일어난다.

LOH에는 큰 메모리들이 할당되고(기준은 85,000바이트라고 한다), GC가 일어날 때,

성능 저하를 피하기 위해서 메모리 재정렬은 하지 않는다.

 

그리고 GC시에는 GC 작업으로 인한 부하를 더 줄이려고, 전용 쓰레드를 쓰고,

또 거기에 로직을 넣고 적절한 시기에 쓰레드를 돌리는 등 여러가지가 있다.

 

Unity Garbage Collector

유니티의 GC는 꽤나 단순무식하다.

그말인즉, 성능은 상대적으로 좋지 않다는 뜻이다.

 

세대 구분? 없다.

SOH와 LOH? 없다.

메모리 재정렬? 없다.

 

그냥 하나의 힙 메모리 영역만 있으며 메모리가 할당되면 죄다 여기에 할당한다.

해제 시 재정렬을 하지 않아, 할당과 해제를 자주하면 메모리에 구멍이 송송 나있어서,

공간은 많은데 메모리 할당을 못하는 경우도 있다.

물론, 내부적으로 메모리가 부족하면 힙 영역을 늘리지만, 결국 근본적인 문제는 해결되지 않고

게임은 메모리 먹는 하마가 된다.

 

게다가 GC시엔 그냥 앱의 다른 동작을 정지시키기 때문에 렉도 심하다.

 

이정도면 너무하지 않나 싶을 정도이다.

 

왜?

왜 유니티는 이런 구린 GC를 쓰는걸까?

궁금해서 구글링을 해봤다.

 

그리고 StackOverflow에서 흥미로운 코멘트를 읽었다.

(검증은 안했으므로 카더라 일수도 있는 점 양해바랍니다.)

 


It was in early 2008 that Unity and Mono announced their collaboration, and at that time Unity licensed the Mono runtime (GPL covered for open source usage) so as to embed it. And the Boehm GC was the primary GC in Mono then.
Time passed and Mono 4.x/5.x by default uses SGen GC with generational/compacting features. However, Unity did not want to pay the licensing again. Thus, you see the documentation remains it was.

Microsoft acquired Xamarin in 2016, and hence gained control of Mono core assets. It republished the code base under MIT, so solving the licensing issue for ever. Unity joined .NET Foundation and started to work with Microsoft/Xamarin to incorporate the latest Mono runtime into the game engine.

That effort is still undergoing and should soon reach maturity (currently an experimental feature).

BTW, Unity cannot use the standard .NET GC yet. Microsoft does not open source its GC in .NET Framework, but a version in .NET Core. That GC is different from Mono's, and would require more efforts to be embedded into Unity. I guess that's why Mono 5 was chosen to be integrated right now. Maybe in the future Unity would migrate to the .NET Core GC.

https://stackoverflow.com/questions/46574407/unitys-garbage-collector-why-non-generational-and-non-compacting

 

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


대충 요약하자면

'과거에 유니티는 가난해서 최신 Mono의 GC를 적용할 돈이 없었어서 초장기 계약한 구식 GC를 계속 사용 중이었다. (구식 C# 버전과 함께)

이제는 Xamarin(Mono개발사)이 마이크로소프트에 인수되어, Mono가 MIT 라이센스로 풀렸기 때문에, 유니티는 최신 버전을 적용할 수 있게 되었고, 열심히 작업 중이다'

 

결국, 유니티는 가난했고, 마소의 자마린 인수 후 오픈소스 정책으로 이제야 적용하는 중이라는 것이다.

 

그래서 찾아보면 현재 유니티가 점진적 가비지 콜렉션을 조금씩 시범 적용 중인 것을 알 수 있는데,

그 기능이 적용된 이유가 아마 이것과 관련이 있지 싶다.

 

결론?

마소를 찬양하라...

아마 마소가 자마린 인수 안했으면, MIT로 전환하지 않았으면,

우리는 아직도 구닥다리 GC와 C#을 사용하고 있었을지도 모른다.

 

 

'Unity' 카테고리의 다른 글

Addressable Asset System에 대한 자잘한 특징??  (0) 2020.05.19
Script Execution Order  (0) 2020.04.05

+ Recent posts