.NET Native简介
这篇Blog好久没有更新了。最近一直在忙.NET Native相关的事情(主要是MCG),但是又因为保密的原因不能在Blog中提到。上个星期Build终于发布(可惜没有去成,team名额太少),我也终于可以谈下.NET Native的一些东西了,呵呵。
如果大家还没有看到之前的发布信息,可以去下面几个网址看看:
http://msdn.microsoft.com/en-US/vstudio/dotnetnative
http://blogs.msdn.com/b/dotnet/archive/2014/04/02/announcing-net-native-preview.aspx
如果英文听力不错的话,可以听一下我们team principal dev lead的talk(其实他的英文比较难懂,速度快。。。):
http://channel9.msdn.com/Shows/Going+Deep/Inside-NET-Native
这里简单讲一下.NET Native的基本架构,基本内容和上面那个talk其实差不多,只是简单给大家讲一下.NET Native的一些基本概念。如果大家有对某个部分具体感兴趣,也可以提出来,我尽量在我能力范围内解答(毕竟不是我一个人做的,呵呵)或者写新的Blog详细解释。
.NET Native和之前的NGEN有本质区别。NGEN实际上是把CLR运行时的数据结构和代码给一锅端(当然,这个是简化的说法,实际上比这个复杂)的放到最终的PE里面去了,运行的时候还是需要整个.NET Framework支持,而且不能避免JIT。.NET Native是全新的技术,整个.NET Framework经过refactoring重写,最终的runtime非常小,只有数百K,无需任何安装(除了mrt100.dll之外,大家可以理解成msvcrt.dll)。大部分的功能都从runtime中refactor到framework中作为C#代码或者作为toolchain一部分存在。一个典型的例子是:P/invoke原来是由CLR实现,使用C++和汇编编写。而现在是经由MCG这个工具接手,直接生成C#。最终.NET Native生成的EXE/DLL是可以直接运行的机器码(通过C++编译器后端生成)。对了,有些朋友可能会问:我们是不是直接生成C++代码?答案是否定的。我们所使用的C++编译器后端接受IL作为输入,生成MDIL。
整个Toolchain(工具链)大致可以分为下面几个阶段:
App IL + FX -> MCG -> Interop.g.cs -> CSC -> Interop.dll -> Merge -> IL transform -> NUTC -> RhBind -> .EXE
第一步:将应用程序的IL代码和整个.NET Framework BCL的IL一起作为输入给MCG。MCG (Marshalling Code Generator)这一块主要是我在负责。这个工具负责检查程序和BCL中所有的Interop相关的类型,比如WinRT接口,P/Invoke,等等。MCG都会为之生成C#代码。这个C#代码是可以直接调试的,有兴趣的朋友可以F11试一下看看。C#代码的作用主要是替代Windows.WinMD中的WinRT类型定义,P/invoke定义,等等,添加各种类型的转换代码,比如字符串类型,RCW和CCW,等等,最终直接调用到本地代码。可能有些朋友会问道:为什么要生成C#? 原来的CLR是直接在运行时生成IL代码的,但是显然这个方法在.NET Native不太适用,而且IL代码很难调试。C#既方便大家调试,也方便我们快速的修改生成的代码,添加更多的功能。(写C++程序生成IL代码可是比较麻烦的,得人工算好stack的位置)
第二步:MCG生成的C#代码通过CSC编译,生成PE文件。这一步没啥可讲的。
第三步:这个PE文件被打包合并到应用程序和BCL,生成一个IL代码的集合。为下一步做好准备。
第四步:这个IL代码的集合会被经过若干的步骤处理,每个步骤都相对简单,只做一件事情。这些步骤的主要作用是提供原来CLR运行时提供的功能,最终的目的是使之最后的代码能够被C++最后编译。在原来桌面版本的CLR里面(也就是4.5里面的那个),很多功能是由Runtime来提供,比如Delegate.Invoke,比如interop。这些Transform的作用是对代码进行处理,把原来需要runtime实现的部分用实际代码替换掉。举个几个例子:
1. 当你在调用Windows.UI.Xaml.Controls.Button类型的时候,MCG也会生成一个对应的Button类型,然后IL Transform会将两者进行替换,这样程序调用的Button类型就是MCG生成的代码了。
2. 当你在进行Serialization和Deserialization的时候,IL Transform会调用另外一个工具SG来生成serialization/deserialization的C#代码,最终这些操作都有这些C#代码生成。3. 你的程序多半不会用到整个BCL。IL Transform中会有一步叫做Dependency Reducer,使用类似GC的算法(mark->sweep),去掉不需要的代码。MCG也和DR通力合作,减少不必要的interop代码生成。DR也会读取RD.XML文件,决定那些类型需要反射信息,那些不需要。RD.XML这一块我们还在改善之中,也希望大家多提宝贵意见。
其实呢,MCG其实也是IL Transform的一部分,只不过它实际上不Transform而已,而是直接生成C#。
第六步:RhBind负责对MDIL进行处理,将里面和类型系统相关的信息生成代码,最后生成一个EXE。其实最终是一个EXE+DLL,实际的代码都在DLL中。EXE只是起到Bootstrap的作用。选用DLL的原因是我们需要支持作为Background Task在Broker里面加载。
几个我听到的常问的问题(如果有些答案过于“官方”,请谅解):
1. 你们最后是生成C++代码吗?
答:不生成。C++后端直接从IL转换成MDIL。
2. WPF支持吗?
答:暂时不支持。目前暂时只支持Windows Store Apps
3. 这个会支持桌面程序吗?
答:目前暂时只支持Windows Store Apps
4. 这个支持JIT吗?
答:目前.NET Native不支持JIT,所有代码都是编译时候生成。
5. 既然是本地机器码,为什么还可以支持类型反射(reflection)?
答:机器码和反射并不冲突,我们在PE文件中储存了额外的用于反射的信息,然后动态读取此信息进行调用。C++也可以支持反射(RTTI),只是不如.NET强大而已。
6.这个需要安装.NET Framework吗?
答:开发编译的时候需要,运行时不需要。
7.为什么不支持VB
答:VB本质上和C#都是生成IL,技术上非常类似。只是目前我们因为时间问题,暂只支持C#。
8.为什么启动运行速度会变快?
答:一方面归功于C++的优秀的编译器后端,一方面也因为runtime的重写和简化。
http://social.msdn.microsoft.com/Forums/en-US/home?forum=dotnetnative
[email protected]
如果不想写英文的话(其实写中文也行,最后多半得我代为翻译),也可以直接在本blog留言。
--
张羿
.NET Native
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。