[Unity] Native의 이해
댓글 0
댓글을 작성하려면 로그인이 필요합니다.
아직 댓글이 없습니다. 첫 번째 댓글을 작성해보세요!
Native라는 단어는 개발하며 자연스럽게 접하게 되는 익숙한 단어다. 이 글에서는 Native가 무엇인지 정의하고 Native Code와 Native Object를 구분해서 서술한다.
Native는 런타임 없이 실행되는 것들이라는 뉘앙스가 있다. 이 단어가 붙은 것들은 하드웨어나 OS 위에 실제로 존재하는 것으로 정의할 수 있다.
C나 Cpp로 작성된 코드는 컴파일 시점에 플랫폼에 맞는 기계어로 변환된다. 이 기계어는 해당 CPU 위에서 직접 동작한다. CPU는 이 언어를 있는 그대로 실행하며, 이러한 기계어 코드가 Native Code이다.
C#은 IL을 거친다. IL이 CLR에 의해 JIT으로 실시간 컴파일되어 기계어로 변환된다. 이렇게 CLR에 의한 변환 과정을 거쳐 CLR의 지원 - 타입 안정성 검사, GC, 예외처리 등을 받아 실행되는 코드가 Managed Code이다.
IL2CPP는 IL을 Cpp로, 그리고 Cpp를 다시 플랫폼에 맞는 기계어로 컴파일(AOT) 해두는데, 이는 IL2CPP가 Native Code를 만든다는 것을 의미한다. 다만 IL2CPP는 그와 동시에 libil2cpp라는 런타임을 사용한다. 이 런타임이 CLR의 역할을 하므로, Native Code일지언정 그 메모리가 Native로써 관리되는 것은 아니다.
Cpp의 new로 생성한 객체는 Unmanaged Heap에 들어간다. 이곳의 객체는 CLR이 관리하지 않아 GC의 지원이 없으니, 할당부터 해제까지 직접 해주어야한다. 이 메모리에 있는 객체들을 NativeObject라 부른다.
C#의 new로 생성한 객체는 Managed Heap에 할당된다. 이 객체에 대해 GC가 도달가능성을 판단하고, 도달 불가능해지면 수거하므로 자동으로 수명이 관리된다. 이처럼 런타임의 관리 체계에 의존하는 객체가 ManagedObject다.
오늘의 글은 좀 쉬운 내용이다. 전에 다룬 이미 다 아는 이야기를 지금 또 다루는 이유는, 다음 장부터 Unity 엔진의 내부를 본격적으로 살펴볼 것이기 때문이다.
우리가 Unity에서 다루는 GameObject, Transform, Mesh, Texture 등과 같은 데이터 등은 Cpp로 할당되고 관리된다. 동시에 우리는 이들에게 접근할 수 있는 C# 핸들 객체를 통해 로직을 작성하고 있다.
즉, Unity에서는 동시에 두 메모리가 공존하며, 이들을 연결하는 무언가가 존재한다. 두 메모리의 경계에서 일어나는 자세한 일들을 다음 장부터 다룰 것이다.