유니티의 iOS 빌드는 왜 다른가?

Unity3D 2014. 11. 25. 20:24
반응형

 

http://www.unitystudy.net/bbs/board.php?bo_table=dustin&wr_id=365

 

최근에 iOS에서 에러가 난다는 문의를 자주 접하는데, 왜 iOS만 문제가 일어나는지, 관련된 내용을 한번 정리해보았습니다. 
제가 가상머신쪽의 전문가는 아니라서 부족한 부분이나 틀린 부분에 대해 회원 여려분들이 의견 주시면 감사하겠습니다. 
( 이 글은 앞으로 자주 수정될 예정입니다. )

[유니티 스크립팅 시스템]
유니티는 모노(Mono)라 불리는 마이크로소프트의 .NET프레임웍을 멀티플랫폼으로 확장시킨 오픈소스 프로젝트에 기반을 둡니다.
마이크로소프트의 .NET프레임웍은 가상머신 위에서 다양한 언어를 지원할 수 있도록 유연하게 설계되어있으며,  프론트엔드(Frontend)에서 제공하는 언어를 MSIL이라 불리는 중간 언어로 변환하고 중간언어를 각 플랫폼에 맞게 최적화시키는 유연한 구조를 가집니다.
이러한 구조는 변환과정에서 부가적인 작업이 발생되어 느리다는 단점이 있는데, .NET기술의 핵심은 JIT컴파일 기술을 통해 가상머신이 관리하는 언어체계를 실제 플랫폼에서 동작시킬때 변환하는 작업의 부하를 줄여주는데 있습니다.
JIT의 약자는 Just in Time인데, 말 그대로 처음에 가상 머신의 언어로 만들어진 코드가 실행되면 이 순간 .NET 프레임워크에 의해 플랫폼이 사용하는 네이티브 코드로 변환되며, 코드가 다시 실행되면 이미 변환된 네이티브코드를 재활용하여 사용합니다.
이 JIT 기술을 통해 기존의 가상 머신 체계가 가지고 있던 성능 저하의 문제점을 극복하게 되었고, 널리 사용되게 되었습니다.

[아이폰은 뭐가 문제인가요?]
.NET프레임웍은 다양한 OS와 언어를 수용할 수 있는 기술이지만, MS가 자사 운영체제인 Windows에만 신경썼던 것과 달리, 유니티가 사용하고 있는 모노 프로젝트는 다양한 플랫폼에서 .NET의 JIT 기술을 활용할 수 있도록 노력하였습니다.
하지만 애플에 와서는 문제가 발생하게 됩니다.
바로 애플이 사용하는 LLVM이라는 인프라때문인데, .NET 프레임웍과 큰 의미에서 유사한 가상 기계에 기반한 설계구조를 가지고 있는 LLVM을 애플이 OS레벨에서 전폭 지원하게 되면서 두 시스템간에 충돌이 발생하게 됩니다.

[LLVM은 뭔가요?]
LLVM의 약자는 원래 저수준 가상 기계(Low Level Virtual Machine)를 의미하였지만, 지금은 가상 기계의 개념보다는 언어와 플랫폼에 독립적으로 최적화된 컴파일을 수행해주는 다양한 컴파일러 인프라로 확장되어 사용됩니다.  
여러가지 전략적인 이유로 2000년도 중반부터 애플사는 LLVM 기술에 전폭적으로 지원하고 있으며, 특히 아이폰 iOS에서 LLVM 체계는 운영체제와 소프트웨어 도구까지 연결된 핵심 인프라로 설정됩니다.

[LLVM과 .NET프레임웍은 서로 뭐가 문제인가요?]
iOS는 LLVM에 기반되어 만들어진 프로그램만 동작하도록 설계되어 있습니다. 
따라서 LLVM과 유사한 개념의 .NET프레임웍을 포함해 Java 및 플래시와 같이 가상 머신 기반에서 JIT 방식으로 동작되는 프로그램들의 동작은 iOS에서 허용하지 않기 때문에 문제가 발생하게 됩니다.

[모노는 이를 어떻게 해결하게 되었나요?]
이러한 제약으로 인해 모노는 아이폰 운영체제에 한해서 일반적으로 .NET프레임웍이 사용하는 런타임에서 네이티브코드를 만들어내는 JIT 방식을 버리고, 컴파일시 LLVM 구조에 맞는 중간 코드(LLVM IR)로 변환한 후 LLVM에서 직접 네이티브 코드를 만들어내는 우회 기술을 만들어냅니다.
이러한 기술은 런타임이 아닌 컴파일시에 진행되기 때문에 통칭 AOT(Ahead of Time) 라고 부릅니다. 
모노뿐만 아니라 어도비의 플래시도 슈퍼 갑인 iOS용 컨텐츠 제작을 위해 현재 구조를 변경하여 액션 스크립트 코드를 LLVM에 맞추는 AOT 방식을 도입하게 됩니다.

[이로써 문제는 완벽히 해결되었나요?]
이러한 변환 과정에서 LLVM 구조에서 지원받지 못하는 .NET 프레임웍의 기능들이 생기게 되었습니다. 대표적인 예가 .NET의 Reflection 기능입니다.

[Reflection이란?]
Reflection은 런타임에서 만들어진 객체를 분석하고, 구조와 설계를 변경할 수 있는 기능을 통칭합니다. 
.NET에서 제공하는 Reflection의 기능은 크게 3단계 정도로 구분할 수 있습니다.
1. 단순히 객체의 정보를 얻어내는 기능
2. 런타임에서 객체를 생성하고 함수를 실행시키는 기능
3. 런타임에서 IL명령어로 객체 타입 및 함수를 제작하는 기능

[Reflection의 기능은 모두 사용이 불가능한가요?]
Reflection 기능을 모두 다 사용이 불가능한 것은 아니고 1번 및 2번의 경우에는 사용시 문제가 없습니다. 
하지만 3번 기능은 현재 사용이 불가능합니다.
Reflection외에도 다른 여러 제약 사항들이 있는데, 아래의 홈페이지 링크에서 확인이 가능합니다.
http://docs.xamarin.com/guides/ios/advanced_topics/limitations

[배경은 이해했다 치고, 그러면 실제적인 문제점은 무엇인가요?]
Reflection에 기반을 둔 .NET의 고급 기능인 Linq와 Linq를 사용하는 .NET의 최신 라이브러리들이 문제를 일으킵니다. 대표적인 클래스가 XMLSerializer라고 할 수 있습니다.
다른 플랫폼에서는 잘 동작하는데, iOS에서만 동작하지 않고 컴파일시 에러 메시지에 Reflection 어쩌구.. 하는 로그가 뜬다면, 대부분 사용하는 라이브러리가 문제 있는 기능을 사용해서 그렇다고 보시면 됩니다.

[iOS를 위한 올바른 유니티 코딩방법은?]
C++ 코딩을 하다 .NET으로 들어오게 되면서 Reflection 기능을 사용하면 모두들 신세계를 경험하게 됩니다.
여기에 현혹되어 스크립팅에서 Linq 및 Reflection, Generic과 같은 고급 문법들을 마구 사용하게 된다면, 안드로이드에서는 쌩쌩 동작하나, iOS 변환시 문제가 발생하는 불상사가 일어나게 됩니다. 
그래서 자세히 조사하긴 싫고 문제를 일으키고 싶지 않다면 .NET 2.0 API만 사용하여 단순하게 작성하는 것을 권장합니다. 
하지만 .NET 3.5이상의 고급 문법으로 생산성과 가독성을 높이고 싶다면, 위에서 알려준 링크를 정독하시고, iOS에서 발생하는 모노의 제약사항을 명확히 인지하고 사용하여야 합니다.

( 이 글은 향후 자주 수정될 예정입니다. )
반응형

'Unity3D' 카테고리의 다른 글

litJson에서 %문자가 파싱 되지 않는 현상  (0) 2014.11.26
List 검색  (0) 2014.11.26
Excel to json converter  (0) 2014.11.25
Return random `list` item by its `weight`  (0) 2014.11.05
unity3d Magnetic move particles  (0) 2014.11.05
: