http://www.blogcn.com/user8/flier_lu/index.html?id=1550010&run=.04005F8
Jeffrey Richter曾在
CodeGuru上发表过一篇讨论是否应该使用NGen的文章。(ngen.exe支持将CLR格式的IL代码编译成Native的代码,避免载入时再次JIT编译)
JIT Compilation and Performance - To NGen or Not to NGen?
文中的观点是应该在大多数程序中避免使用ngen预编译IL代码为Native代码,因为JIT编译器可能比ngen更了解用户的系统。例如JIT编译器有以下优势:
1.可以知道用户正在使用的什么类型的CPU,是PII、PIII还是P4,并编译生成相应的优化指令
2.可以知道用户当前是使用单CPU还是多CPU,以便优化线程锁定机制
3.可以避免ngen静态编译带来的DLL载入时重定位问题等等
而且使用ngen预编译代码还会带来一些潜在的问题:
1.没有知识产权保护:与某些人预期的不同,ngen生成的Native代码不能独立发布。因为其中没有包含Metadata信息,所以还是必须与原始的IL代码一同发布
2.ngen生成的文件可能不同步:CLR在载入ngen生成的文件时,要检测其编译时的属性是否与当前环境匹配,不匹配则使用缺省的JIT编译
3.难以管理:ngen生成的文件不能自动删除,因此违背了.NET架构程序的XCOPY分发策略
4.低劣的载入时性能(重定位):如果ngen生成的DLL文件的基址已经被占用,则载入时需要重定位(rebase)
5.低劣的运行时性能:ngen生成的文件采用较为保守的假定环境,因此代码效率低于JIT编译
6.
某些应用程序域(domain)的载入策略会忽略ngen生成的文件:assembly可以以应用程序域相关(non-domain-neutral)和
无关(domain-neutral)的方式被载入,但ngen生成的文件假设只有mscorlib.dll以应用程序域无关的方式被载入。因此当某个
assembly通过应用程序域无关的方式被使用,则ngen生成的代码无法使用,还是要通过JIT编译。例如ASP.NET中所有具有
strongly-named的assembly都会被通过应用程序域无关的方式载入。
因此Jeffrey Richter认为,只有对于客户端程序能够有可测量的载入性能提升的情况下,才应该使用ngen预编译代码,而对于其他程序,特别是服务器端程序,都应该避免ngen的使用。
不过CLR组的Junfeng Zhang并不十分赞同上述观点,故而在其BLog上发表了一篇批驳的文章
JIT Compilation and Performance - To NGen or Not to NGen?
文中对Jeffrey Richter提出的ngen的几个潜在问题逐条反驳:
1.ngen并不是用来保护知识产权的工具,只是优化载入时性能而已,可以通过其他工具如混淆器(obfuscator)保护知识产权
2.一般只有在维护.NET Framework和自己的程序后,才会导致不同步问题,而此时可以使用ngen重新生成预编译文件
3.ngen支持 /delete 命令行参数,因此可以通过写一个批处理文件完成自动删除
4.重定位是所有dll都存在的问题,并不能为了避免重定位就不使用dll而采用巨大的exe文件,因此这不能作为不使用ngen的理由。而且CLR载入dll的时候会检测这种情况的发生,并在合适的情况下拒绝使用ngen生成的文件
5.CLR
目前的JIT编译器对所有代码只编译一次,而不是象Sun的Hotspot那样,监视已JIT的代码,根据动态行为重新JIT优化性能。而ngen具有的
JIT无法达到的优势是可以跨assembly做一些代码的优化。不过ngen代码还是比JIT编译平均有5%-10%的性能损失,单能大大提高载入速
度。
6.ngen编译的文件的确在某些情况下无法被使用,但这并不能作为不使用ngen的理由
此外ngen还有个优点是其生成的代码可以被多个进程共享,而JIT编译生成的代码在私有地址空间中。
因此ngen在客户端代码的处理上还是有价值的,呵呵
后面MS的Josh Williams又补充说,在64位版本的.NET中,ngen生成代码的性能可能比JIT代码有较大改善,因为ngen包含了一些对JIT来说过于复杂的全局优化措施。
最后Junfeng Zhang还给出了一个性能优化的指导性文章的链接
Profile-Guided Optimization with Microsoft Visual C++ 2005
有趣的讨论,通过这种BLog的论战,很容易就能够获得一些通过正规渠道文章无法了解的内幕消息,呵呵