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