cuclife.com > IT > C# > 0

C#本地代码生成器工具:NGen.exe

网络整理 - 06-27

NGen.exe工具(本机映像生成器)随.NET Framework一起发布,用来在客户机上安装应用程序时,将IL代码编译为本地代码。由于代码在安装时已经编译了,运行时JIT编译器就无需再次编译,这可以提升程序性能。

  • 缩短程序启动时间。
  • 减少程序工作区大小。NGen.exe将编译的本地代码保存为一个单独的文件,该文件可同时被多进程地址空间进行内存映射,每个进程不需要单独的拷贝。

当安装程序对应用程序或单独的程序集调用NGen.exe时,应用程序所用的程序集或那个指定的程序集的IL代码将被编译为本地代码。NGen.exe将生成一个仅包含本地代码的新的程序集文件(不包含IL代码)。这个新的文件位于类似C:\Windows\Assembly\NativeImages_v4.0.#####_64这样的目录下。目录名称包含CLR版本,以及本地代码编译为x86、x64还是Itanium。

现在,当CLR加载程序集文件时,会先查找是否存在相应的NGen后的本地文件。如果没找到,CLR即时编译IL代码。如果存在,CLR将使用已存在的本地文件,并且在运行时不再需要编译文件中的方法。

表面上开来,你好像即得到了托管代码的好处(垃圾回收、验证、类型安全等),又避免了性能问题(JIT编译),似乎很棒。但其实有很多潜在问题:

  • 没有代码保护。使用NGen并非意味着可以不发布包含IL代码的文件。
  • NGen的文件可以不同步。当CLR加载NGen文件时,会比较前期编译的代码和当前执行环境的诸多特征。如果任何一个特征不相符,就不使用NGen文件,取而代之的仍然是普通的JIT编译过程。必须匹配的特征如下:
  • CLR版本:打补丁时会改变。
  • CPU类型:升级硬件时会改变。
  • 操作系统版本:更新SP包时会改变。
  • 程序集的identity module version ID(MVID):重新编译时
  • 引用的程序集的版本ID:重新编译引用的程序集时
  • 安全:撤销许可时
  • 所以必须在更新模式时时对所有程序集再次运行NGen.exe。如更新.NET Framework补丁时,补丁包安装程序将自动运行NGen.exe,使NGen.exe文件与CLR版本保持同步。
  • 运行时性能低下:NGen在编译代码时并不能像JIT编译器那样对执行环境做许多假设。因此NGen生成的是劣等代码。如,NGen无法优化CPU指令的使用;它还添加了对静态字段的间接访问,因为静态字体在运行时之前没有实际地址。NGen在各处插入调用构造函数的代码,因为它不知道代码执行的顺序以及构造函数是否访问过。NGen编译的程序性能通常会损失5%。因此如果你考虑使用NGen改善程序性能,应该比较一下NGen和非NGen版本的性能。

因此,慎用NGen。

对于服务器端应应用,NGen几乎没有意义,因为只有第一次请求会损害性能。而且对于服务器应用,只需要一个代码实例,不需要工作组。NGen生成的映像不能跨应用程序域。类似ASP.NET这种需要跨应用程序域的程序集就没必要NGen了。

对于客户端应用,NGen会改善程序启动时的性能减少工作组,如果程序集同时用于多个程序的话。即使程序集没有用于多个程序,NGen仍然能够改善工作组。此外,如果所有客户端程序都使用NGen,CLR就没有必要加载JIT编译器,这能进一步减少工作组。当然只要一个程序集没有使用NGen或者不能使用NGen,JIT编译器都将加载,并增加工作组。