.NET JIT编译的代码在哪里caching?
一个.NET程序首先被编译成MSIL代码。 当它被执行时,JIT编译器将把它编译成本地机器代码。
我想知道:
这些JIT编译的机器代码在哪里存储? 它只存储在进程的地址空间吗? 但是由于程序的第二次启动比第一次启动要快得多,我认为这个本地代码在执行完成之后一定已经存储在磁盘上了。 但是哪里?
记忆。 它可以被caching,这是ngen.exe的工作。 它生成一个.ni.dll版本的程序集,包含机器代码并存储在GAC中。 之后自动加载,绕过JIT步骤。
但是,这与你的程序第二次启动的速度没有多大关系。 你第一次有所谓的“冷启动”。 这完全由在硬盘驱动器上查找DLL所花费的时间所支配。 第二次,你有一个温暖的开始,DLL已经在文件系统caching中可用。
磁盘很慢。 SSD是一个明显的修复。
Fwiw:这不是托pipe代码专有的问题。 大型非托pipe程序与大量的DLL也有它。 目前在大多数开发机器上的两个规范示例是Microsoft Office和Acrobat Reader。 他们作弊。 安装时,他们将“优化器”放在运行registry项或启动文件夹中。 所有这些优化器所做的就是加载主程序使用的所有DLL,然后退出。 当用户随后使用该程序时,这将启动文件系统caching,因为它的热启动很快,所以它将快速启动。
我个人觉得这非常烦人。 因为他们真正做的是放慢任何其他程序,我可能要login后启动。这是很less的Office或Acrobat。 我要说删除这些优化器的时候,如果有必要的话,当一个blasted更新放回去的时候可以重复。
你也可以使用这个技巧,但请使用它负责任的。
正如其他人所指出的那样,代码在每个进程的基础上都是JIT,并且没有被caching – 在第二次加载时看到的加速是组件的OS磁盘caching(即内存)。
然而,虽然在框架的桌面\服务器版本中没有caching(除了操作系统磁盘caching),但在另一个版本的框架中caching了JIT的机器代码。
感兴趣的是.Net Compact Framework(适用于Windows Phone 7的NETCF)。 最近的进展看到JIT的代码确实被caching的进程之间共享一些JIT的框架代码。 这主要是为了获得更好的性能(加载时间和内存使用)在受限设备(如手机)中执行。
因此,在回答这个问题时,在CLR的desktop \ server版本中没有JIT代码的直接框架caching,但是最新版本的紧凑框架即NETCF。
参考:我们相信分享
http://blogs.msdn.com/b/abhinaba/archive/2010/04/28/we-believe-in-sharing.aspx
JIT编译的机器代码在每个方法的内存中被caching,每次方法被第一次执行。 我不认为它曾被caching到磁盘。
您可能会发现,由于Windows在第一次运行时(在内存中)caching了进程(dll,资源等)使用的文件,所以第二次加载的速度更快。 在第二次运行中,不需要到磁盘上,在第一次运行时可能已经完成了。
您可以通过运行NGen.exe来确认这一点,以便为您的架构实际预编译机器代码,并比较第一次和第二次运行的性能。 我敢打赌,由于在操作系统中caching,第二次运行仍然会更快。
简而言之,IL是针对程序的每次调用进行JIT编译的,并保存在进程地址空间的代码页中。 请参阅Richter的第1章,详细介绍.NET执行模型。
我相信JIT编译的代码从不存储或交换内存不足。 您在程序集的第二次执行中感觉到的性能提升是由于相关程序集已经在内存或磁盘caching中。
是的,即使MSIL版本不存在,NGEN.EXE也会在GAC中放置一个.NET可执行文件的JIT编译版本。 我已经尝试过,但无济于事。 我相信,除非原始的MSIL版本也在GAC中并且从那里加载,那么GAC中的JIT版本将不会被使用。 我也相信即时JIT编译( 而不是 NGEN)不会被caching; 他们只占用进程内存。
我相信这从阅读MS文件和各种实验。 我会欢迎来自“知道者”的确认或反驳我的断言。