빌드 설정의 Configuration - Scripting Backend를 본다면 Mono와 IL2CPP라는 항목을 볼 수 있다.
디폴트로는 Mono로 설정이 되어있는데 Mono는 무엇이며 IL2CPP는 무엇인지 공부해봤다.
유니티의 속사정
'유니티는 C#이기 때문에 느리다' 라고 하는 사람들도 많이 있다.
하지만 유니티는 엔진 내부는 C++로 만들어져 있고
유저에게 노출되는 API와 유저 스크립트만 C#이다.
C++ 과 C#
C++ 부터 객체지향, Class를 사용할 수 있고 메모리를 '직접' 관리해야 한다.
New라는 키워드로 생성을 하고 Delete라는 키워드로 메모리 할당을 해제해줘야 메모리 누수가 발생하지 않는다.
C#은 마이크로소프트사의 닷넷 프레임워크를 기반으로 돌아가는 언어인데,
managed memory 를 사용하기 때문에 New라는 키워드로 인스턴스를 생성만 하고 나중에 가비지가 되면 가비지 콜렉터라는 녀석이 다 치워준다.
그래서 C#은 생산성이 높고 직접 메모리 관리를 신경 쓸 필요가 없지만 이 이점이 성능을 떨어뜨리게 된다.
즉 , managed memory 를 사용하여 개입이 많기 때문에 C++ 보다는 성능적으로 떨어진다.
Mono FrameWork
유니티는 멀티 플랫폼을 지원한다.
MS의 닷넷 프레임워크를 기반으로 돌아가는 언어가 어떻게 멀티플랫폼을 지원하냐면
바로 이 mono라는 프레임워크 때문이다.
윈도우만 지원하는 닷넷에 대응하기 위해 만들었고,
여러가지 플랫폼에서 C#을 돌릴 수 있는 리눅스 기반의 프레임워크다.
오픈 소스로 시작했다가 ms가 가져가서 xamarin project로 발전시키면서 mono도 같이 발전했다고 한다.
유니티에서의 멀티플랫폼
유니티에서 멀티플랫폼으로 돌아가는 방식은 이렇다.
C#으로 작성한 스크립트를 IL로 변환을 시킨다.
IL은 Intermediate Language라고 해서 중간 언어이다.(정확히 말하면 닷넷 어셈블리) .NET 어셈블리 | Microsoft Docs
IL은 기계언어도 아니고 ,High 레벨 언어도 아니고, 그렇다고 완전히 Low 레벨 언어도 아닌 정말 중간단계 언어라고 한다.
그 다음 이 IL을 모노 프레임워크에서 돌리는데,
모노가 런타임상에서 실시간으로 파싱을 하며 여러가지 플랫폼에서 돌아간다.
이걸 JIT 방식이라고 한다.
AOT 방식 , JIT 방식
우리는 2가지의 컴파일 방식을 알아야하는데
AOT와 JIT 방식이다.
AOT (Ahead Of Time)
- 단어의 뜻에서 알 수 있듯이 소스코드를 미리 컴파일 하는 방식이다.
JIT (Just In Time)
- AOT와는 반대되는 개념으로 런타임상에서 컴파일을 진행한다.
(모든 코드들을 다 런타임상에서 컴파일 하지는 않을수도 있다고 한다.)
JIT 방식은 인터프리터 언어와 같을까?
인터프리터(interpreter)는 통역사라는 뜻인데,
Lua , 파이썬 같이 쌩 언어 자체를 실시간 파싱하면서 돌린다.
즉,유저가 작성한 코드를 실시간으로 통역사가 통역하며 컴퓨터 언어로 바꿔준다.
그렇기 때문에 굉장히 느리다는 단점이 있는데
JIT 방식은 이미 1번 변화된 중간 형태인 IL(C#에선 넷 어셈블리)를 가지고 타겟 디바이스에 맞게 컴파일 하기 때문에
인터프리터 방식보다는 빠르다.
그래서 IL2CPP란?
모노 프레임워크가 C#을 IL로 바꿔주는건 그대로지만
바로 이 IL을 C++로 바꿔주는 중간단계가 추가된다.
cpp로 바꿔주게 되면 ios는 object-c 가 있기 때문에 그대로 사용할수 있고,
안드로이드는 Dalvik, ART같은 버추얼 머신상에서 돌아가기 때문에 내부는 결국 native 이기도 하고,
NDK(Native Development Kit) 를 지원해주기 때문에 C++로 돌릴 수 있는것이다.
IL2CPP를 사용하면 스크립트도 CPP로 사용하기때문에 멀티플랫폼에서 사용할 수 있고
기존의 mono로 돌리는 방식보다 성능을 향상 시킬 수 있다.
그리고 IL2CPP를 사용하게 되면 JIT 방식이 아닌, AOT방식으로 컴파일 한다.
또, IL2CPP로 설정 해두어도 에디터상에서는 JIT방식으로 실행 된다고한다.
(최종 빌드 결과물은 IL2CPP)
IL2CPP 설정
최신 유니티 버전을 깔아보면 위와 같은 설정이 생겼는데, (골드메탈님의 강의를 대비해 2022.1.5f1 버전을 깔아두었다)
스크립팅 백앤드를 IL2CPP로 바꾸면 활성화된다.
이 두방식을 알기위해선 C++의 템플릿과 , C#의 제네릭을 알아야한다.
C#의 제네릭 ,C++ 의 템플릿
두 언어에는 형식을 미리 정해두지않고 사용할때 상황에 따라 정할 수 있는 방식이 존재한다.
C#의 제네릭은 <T>로 설정을 해주고 나중에 사용할때 원하는 형식을 넣어서 사용한다.
C++의 템플릿도 C#의 제네릭과 같은 기능을 한다.
사용한 타입이 많으면 많을수록 그 코드를 다 컴파일 전에 작성하기 때문에 코드가 길어진다.
Call by Value , Call by Reference
콜바이 밸류는 값자체를 복사하여 넘겨주는 방식이고,
콜바이 레퍼런스는 주소값을 넘기는 방식이다.
CPP
이런 A라는 구조체가 있다고 가정해보자.
하단에 적어놓은 코드를 순서대로 1, 2, 3이라고 하겠다.
1번은 a라는 값 그자체를 복사해서 넘긴다. (콜 바이 밸류)
2번은 포인터로 넘기기 때문에 주소값을 넘긴다.( 콜 바이 레퍼런스)
3번은 &를 붙여서 레퍼런스 타입으로 넘겨줬기 때문에 이것도 주소값을 넘긴다. (콜 바이 레퍼런스)
이런식으로 C++에는 포인터와 레퍼런스 타입이 존재하기 때문에 다양하게 인자값을 선택해서 넘겨줄 수 있다.
1번은 6*4 = 24 바이트의 메모리가 들지만 사용하기가 쉽다.
2,3번은 8바이트의 주소 메로리가 들지만 사용하기가 어렵다.
C#
반대로 C#에서는 이 넘겨주는 타입이 정해져있다.
만약 int을 넘긴다면 콜바이 밸류로 넘겨버리고
string을 넘긴다면 콜바이 레퍼런스로 넘겨버린다.
눈치 채신분도 있겠지만 데이터가 작은 타입이면 값타입으로 넘기고 크다면 레퍼런스로 넘긴다.
유니티에서 많이쓰는 가장 대표적인 제네릭은 GetComponet<T> 가 있다.
두 언어의 차이에서 오는 문제점
C#의 제네릭을 C++의 템플릿으로 바꾸기 위해서는
Value 타입인지, Reference 타입인지
AOT 방식인지 JIT 방식에서 오는 차이 때문에 CPP의 템플릿으로 바로 변환이 안된다.
C#은 JIT방식이 때문에 기본적인것만 만들어놓으면 나머지는 그때그때 필요할때 만들어서 쓰지만
CPP는 AOT 방식이기 때문에 미리 만들어둬야해서 코드 길이가 엄청 나게 길어진다.
그래서 IL2CPP방식을 쓸 때 제네릭을 많이 썼다면 그만큼 변환 과정이 길어지고 빌드가 오래걸린다.
처음에 언급한 설정으로 다시 돌아와서 위의 내용을 기반으로 얘기를 한다면
첫번째 옵션인 Faster Runtime은 기존 방식이다.
C#의 레퍼런스 타입들은 C++의 포인터로 대충 퉁 쳐서 만들어내고,
값 타입들은 다 풀어서 코드를 만들어낸다.(미리 만들어둬야 하기 때문에)
그래서 코드사이즈도 커지고 컴파일 시간도 오래걸린다.
두번째 옵션인 Fater builds는
값 타입들도 포인터로 한겹 더 싸서 하나의 공유 코드로 퉁쳐서 만들어버린다.
코드를 첫번째 옵션과 같이 하나하나 풀어내지 않으므로 코드사이즈가 줄고 빌드시간도 줄어든다.
하지만 포인터로 받기 때문에 타입을 추론하고 원래 데이터로 복구하는 과정에서 런타임성능이 떨어진다.
그래서 지속적인 빌드로 테스트를 해봐야 하는 개발단계일때는 두번째 옵션을 사용하고,
최종 결과물을 만들때는 첫번째 옵션을 사용하는것을 권장했다.
시청한 영상 & DOTS
위의 영상을 통해 IL2CPP를 공부 해봤다.
이 영상 말고 이 영상의 풀버전에 Burst라는 유니티 전용 DOTS 기반 컴파일러에 대한 내용이 나오는데 정말 흥미로웠다.
DOTS(Data-Oriented Technology Stack 데이터 지향 기술 스택)의 약자로
멀티쓰레딩과 퍼포먼스 향상이 가능한 차세대 유니티 기술이다.
기존의 object - oriented 디자인의 유니티의 전통적인 방식이 아닌, 데이터에 초점을 맞춘 아키텍쳐라고 한다.
DOTS를 사용한 스튜디오의 게임영상을 보여줬는데
이렇게 많은 몹들을 어떻게 썼지 싶으면서도 대포로 날려버리는게 시원하다.
DOTS라는걸 더 알아보고 싶지만 취준하는 입장에서 우선순위가 다른게 훨씬 많이 앞에 있기때문에..
나중을 기약하며 글을 마친다.
DOTS에 관심있으신 분들은 아래 링크로 가서 보셔도 좋을것같다.
DOTS - Unity의 새로운 멀티스레드 데이터 지향 기술 스택
[Unity] DOTS란 무엇인가? Unity ECS 시스템 요약 - 프로 찍먹러의 게임 세상 (tistory.com)
'게임 엔진 > Unity' 카테고리의 다른 글
[Unity] 포톤서버를 이용해 간단한 말풍선 채팅 만들어보기 (0) | 2022.09.25 |
---|---|
유니티 박스(장애물) 높이별 점프 구현해보기 (0) | 2022.08.15 |
[유니티 공식 유튜브] 모바일 게임 성능 최적화 - 2편 (0) | 2022.08.07 |
[유니티 공식 유튜브] 모바일 게임 성능 최적화 - 1편 (0) | 2022.08.01 |
유니티 알쓸유잡 - 병목현상 (0) | 2022.07.24 |
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!