这两天一直在准备Session,从老外的PPT里发现,原来.NET CF 1.1中,支持两种JIT——sJIT和iJIT,赶紧搞搞明白。没想到google到了这样一篇文章,学习一下搞明白了。于是草译出来给大家分享。
原文在:http://www.danielmoth.com/Blog/2004_12_01_mothblog_archive.html。
----
现如今,所有的.NET开发者都知道托管代码(用C#、VB.NET写的)都是被编译成中间语言(IL,Intermediate Language)的,在运行时,再由即时编译器(JIT,Just-In-Time)编译成本机代码。这里我们对.NET CF中的JIT引擎和桌面(.NET“完整版”)进行一个比较,并看看.NET CF 2.0中的变化。
回首往事,alpha(pre-RTM)版的CF并没有JIT编译器,IL都是在设备上进行解释的。直到RTM版本的出现(关于CF的版本请看这里),设备上的IL才被JIT成本机代码。这种编译以方法为单位(和完整版一样)。当调用一个方法时,如果没有与这个方法对应的本机代码,则IL被编译为本机代码并执行;下一次只要直接执行该方法的本机代码即可。这意味着JIT带来的性能损失只会出现一次。
主要的区别在于CF将本机代码环存在GC堆里(也就是RAM里),并且在发生完全GC时会发生性能“颠簸(Pitching,不知道这么翻好不好)”(有关GC的阶段,请参见这里)。换句话说,JIT生成的本机代码,会因为内存压力的增大而被丢弃,因此下一次调用一个方法时,还要重新进行编译,因此性能发生了颠簸(忽快忽慢的意思吧?)。不要把Picthing方法和实际类型的数据结构(元数据)搞混,元数据只要加载完毕后就不会“颠簸”。
要获得你的CF应用程序的有关数字(数据),请使用性能计数器。尤其关注这几个:Bytes Jitted、Native Bytes Jitted、Number Of Methods Jitted、Bytes Pitched和Nummber Of Methods Pitched。
另外一个区别就是.NET CF不支持ngen。因此您不能将程序集预编译成本机镜像。
最后,JIT生成的代码大小被限制为64K(译注:2.0里据说取消了这个限制)。您不能超过这个限制,但大型的窗体可能会导致自动生成的InitializeComponent方法的大小超出这个限制。解决的方法就是把这个方法拆分成多个比较小的方法(代价就是失去窗体设计器支持)。
CF 1.0中有两种JIT编译器:sJIT和iJIT。前者专用于ARM设备,后者用于其他架构的CPU(包括SH3、MIPS、x86)。sJIT在将IL编译为本机代码时要耗费比较长的时间,但生成的代码比iJIT生成的快(这个PPT中有详细的说明)。
CF 2.0使用统一的JIT,这比现有的JIT更高效,经过的优化更多。随VS2005发布的模拟器使用ARM架构的CPU(而不是现有的x86架构),所以从性能的角度来看,强了许多。
如果您还记得我读过的所有CF的书,我可以告诉您Building Solutions with the CF和CF Kick Start两章都有一些段落是描写JIT的。.NET CF Bible也贡献了几页,用于介绍JIT代码池/本机镜像缓存。
新年快乐!(没办法,原文04年12月31号写的。)