这期内容当中小编将会给大家带来有关怎么理解.NET Native架构,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。
这里简单讲一下.NET Native的基本架构,基本内容和上面那个talk其实差不多,只是简单给大家讲一下.NET Native的一些基本概念。
.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#。
第五步:NUTC对IL进行处理,生成MDIL。NUTC就是传说中的C++的编译器后端的一个特殊版本,优化什么的就靠它了。最后生成的MDIL接近机器码,但是也包含一些抽象的类型信息,需要进一步处理。
第六步: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的重写和简化。
上述就是小编为大家分享的怎么理解.NET Native架构了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注亿速云行业资讯频道。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。