게임엔진/유니티 12

IL2CPP가 Virtual Call과 Boxing을 처리하는 방법

이 글의 정보들은 2016년에 작성된 글을 기반으로 함. 따라서 2023년 현재 바뀐 부분이 있을 수 있음. Devirtualization 당연한 얘기지만, Virtual Call은 Direct Call보다 더 느리다. 따라서 일부 컴파일러는 Virtual Call을 Direct Call로 바꾸는 Devirtualization 기법을 사용하기도 한다. 단, 해당 코드가 컴파일 타임에 어떤 메서드를 실행시킬지를 판단할 수 있어야 한다. 이는 IL2CPP도 마찬가지이다. 다만 IL2CPP는 최적화에 보수적이기 때문에... var dog = new Dog(); //Dog는 Animal 클래스를 상속함. dog.Speak(); 위와 같은 상황에서도 Virtual Call을 호출하는 C++코드를 만들어낸다. (2..

(협업) Unity Accelerator - 임포트 시간 단축

에셋 임포팅 에셋 데이터는 CPU GPU등의 하드웨어에서 즉시 쓰일 수 있는 포맷일 필요가 있다. 그러나 대부분의 파일 포맷은 저장공간을 최소화하도록 되어있다.(압축) 따라서 유니티는 저장공간에 있는 데이터를 에셋 데이터로 컨버전 한다. 그리고 이렇게 변환된 에셋 데이터는 라이브러리 폴더에 캐싱된다. 이 과정을 에셋 임포팅이라 한다. 문제는? 근데 에셋 임포팅은 오래 걸림. 변경이 많으면 많을수록 더 오래걸린다. 만약 아예 모든 에셋을 임포트 해야 하는 상황이거나 플랫폼을 바꿔야 하는 경우라면 더욱 더 오래걸린다. 그러면 이걸 어떻게 해결할까? 임포트된 에셋 데이터는 라이브러리에 캐싱된다. 따라서 팀내에서 라이브러리 폴더를 공유할 수 있다. 플랫폼 스위칭 같은 경우를 대비하여 플랫폼별로 라이브러리 폴더를..

Update()

Update()는 어떻게 실행되나? Monobehaviour을 상속한 클래스 내에서 Update() 메서드를 정의하면 해당 메서드는 매 프레임마다 유니티에 의해 실행된다. 그럼 어떻게? Update()메서드를 private로 선언하건, protected로 선언하건 항상 수행되는 것을 보면 리플렉션 따위를 써서 메서드 이름을 얻어오고 어딘가에 캐싱한 다음 매 프레임마다 호출할 것으로 예상해볼 수 있다. 이게 아무것도 없는 빈 Update()메서드를 정의하지 말아야 하는 이유이기도 할 것이다. Update()의 성능은? 10000개의 Monobehaviour 객체를 매 프레임 업데이트 하고 싶다고 하자. 이 때 두 가지 방법이 가능하다. 하나는 Monobehaviour에 Update()를 정의하는 것. pr..

(토막상식) NativeContainer

Native Container Native Container는 native memory(unmanage)에 대한 wrapper이다. (Thread-Safe를 지원) native memory에 대한 버퍼를 managed code영역으로 노출하는 array, map, set등을 가지고 있음. 기본적으로는 Safety-Check를 수행하는데, unsafe로 시작하는 애들은 안 함. 그래서 당연히 native를 쓰는 게 더 좋겠지만 Native Container안에 Native Container를 담을 수는 없어서 unsafe를 써야 할 때가 있긴 하다. Access 정해주기 기본적으로 job 따위가 NativeContainer 인스턴스에 접근하면 read/write 둘 다 가능함. 그러나 이건 비효율적인데 r..

(토막상식) 유니티 메모리

메모리 종류 Managed Memory : GC가 적용되는 유저 영역의 메모리 레이어. Umanaged Memory(C#) : GC가 적용되지 않는 메모리 레이어, Unity.Collections 패키지를 통해 사용할 수 있는 공간이다. Native Memory(C++) : 유니티 엔진이 돌아갈때 쓰는 C++ 메모리이다. 일반적으로 유저가 접근 불가능한 영역. Managed Memory Mono나 IL2CPP나 VM에 managed memory 시스템이 있다. (=scripting memory system). managed heap : VM이 자동으로 GC써서 컨트롤 해주는 힙 메모리 영역. 여기에 메모리 할당하는걸 GC Allocation이라고도 한다. scripting stack : 그냥 스택영역....

IL2CPP, MONO, AOT, JIT 여러 줄 정리

[유니티 TIPS] 알고 있으면 쓸데 있는 IL2CPP, Mono, AOT, JIT 개념 파헤치기 1. 유니티 엔진 내부는 C++로 짜여있다. 유저 코드 부분만 C#으로 짜여있다. 따라서 유저 코드 부분에서만 C#사용으로 인해 속도가 느리다. 2. IL2CPP로 빌드하면 유저가 쓴 코드도 CPP로 변환된다. 3. C#을 컴파일하면 IL코드가 생성되고, MONO는 IL코드가 다시 여러 플랫폼에서 돌아갈 수 있게 해준다. 4. Mono는 IL코드를 그때그때 컴파일한다. 즉 JIT방식이다. 5. JIT방식은 인터프리터보다는 빠르다. JIT은 인터프리터와 달리 중간 처리된 코드(IL코드)를 컴파일 하기 때문 6. IL2CPP역시 Mono같은 역할을 수행한다. IL코드를 여러 플랫폼에서 돌아갈 수 있게 해주는 것..

예약된(?) 폴더 이름과 Application의 Path들

특수 폴더 이름 유니티는 아래의 몇몇 폴더 이름을 특수한 목적을 위해 예약해 두고 있다. (개발 언어의 예약어처럼) Assets Editor Editor default resources Gizmos Plugins Resources Standard Assets StreamingAssets "Assets" Assets는 유니티 프로젝트에서 쓰이는 에셋들을 담고 있는 주 폴더이다. 대부분의 API가 모든 에셋이 여기에 있다고 가정하고 있다. "Editor" Editor 폴더 안의 스크립트는 에디터 어셈블리에 포함된다. 따라서 런타임에 읽을 수 없다. Editor 폴더는 여러 개가 될 수 있다. "Editor Default Resources" 에디터에서만 사용할 리소스들을 모아두는 폴더. 에디터 전용이기 때문에..

VCS - Plastic SCM

Plastic SCM Plastic SCM이라고 유니티에서 인수한 VCS라길래 한 번 써봄. 우선 Plastic SCM이 주장하는 본인들의 장점은 대용량파일을 잘 다룸 유연함 업로드/다운로드 속도 좋음 Unity/Unreal 플러그인이 있다. 공짜임 (3명 / 5GB) 아티스트를 위한 단순화된 워크플로 (Gluon mode) 요정도이다. 특히 아티스트/디자이너를 위한 글루온 모드(Gluon mode)라는게 있는데 뭐 막 특별한건 아니고 복잡한 기능들은 싹 제거해놓은 버전이라고 보면 될듯? 거기에 더해서 특정 파일을 잠그는게 매우 간편하다. 이렇게 해주면 끝... 그 외에도 대용량파일을 깔끔하게 지원한다. 모드도 중앙형/분산형을 지원하는데, 중앙형은 SVN처럼 바로 Repo에 올리는거고... 분산형은 Gi..

Enter Play Mode Settings

개요 Enter Play Mode Settings란 유니티 2019부터 실험적(Experimental)으로 들어간 기능이다. 2020버전 부터는 정식 지원인듯. Project Settings - Editor 에서 선택할 수 있다. 아무튼 이 기능이 뭐냐면 유니티 에디터에서 Play Mode로 진입하는 속도를 대폭 향상시켜주는 기술이다. 얼마나 속도가 빨라지는지는 아래를 보자. 원리 당연히 잃는 것 없이 실행 속도가 빨라졌다면 유니티에서 굳이 옵션으로 제공하지 않았을 것이다. 속도를 향상시키기 위해서 유니티에서는 도메인과 씬의 Reload과정을 생략한다. 도메인 리로드 도메인 리로드에서는 다음과 같은 일을 한다 스크립트 직렬화 유니티 도메인 언로드 새로운 유니티 도메인 생성 스크립트 역직렬화 도메인이란 대..

어드레서블 (Addressable) - 1. 기본

어드레서블 에셋 시스템 어드레서블 에셋 시스템은 에셋 번들을 대체하는 기술이 아니다. 그냥 에셋 관리의 편의성을 위한 유틸리티라고 보면 된다. 간단하게 말하면, 아래와 같이 에셋에 주소(address)를 부여해주는게 어드레서블의 핵심이라 할 수 있다. 그리고 어드레서블 에셋 시스템은 이러한 주소를 이용하여 에셋의 관리, 로딩, 빌드를 통합한 시스템이다. 어드레스(address) 에셋에 부여된 어드레스(address)는 다음과 같이 활용할 수 있다. 버튼을 누르면 지정된 프리팹을 생성하는 Spawner가 있다고 하자. 위와 같이 프리팹을 직접 연결하는 방식은 스포너가 생성되는 순간 연결된 프리팹도 메모리에 올라가서 좋지않다. 이를 위해 직접 에셋의 경로를 Spanwer에 전달하는 방식을 써야 한다. 보통 ..