如何证明.NET CLR JIT每次运行只编译一次方法?

时间:2017-02-15 23:40:46

标签: c# .net clr windbg jit

an old question询问C#是否每次都是JIT编译,着名的Jon Skeet的回答是:“不,每个应用程序只编译一次”,只要我们讨论的是非NGENed的桌面应用程序

我想知道2009年的信息是否仍然存在,我想通过实验和调试来解决这个问题,可能是在JITter上放置断点并使用WinDbg命令检查对象和方法。

到目前为止我的研究

我知道.NET内存布局在实际数据开始之前(地址A + 4)考虑每个对象的Header(地址A-4)和方法表(地址A + 0)。因此,每个对象可能有不同的方法表,因此可能有不同的JITted方法。

为什么我对声明的正确性有疑问?

我们有一个并行编程研讨会,培训师提出的一个主张是每个线程的每个对象都有JIT。这显然对我没有意义,我能够编写一个反例示例。

不幸的是,出现了以下其他主题,我也想写一个演示:

  • 新的.NET框架
  • 申请域
  • 代码访问安全性

链接的答案是在.NET 3.5发布时编写的。从那以后它没有实质性改变,即它没有收到.NET 4.0,4.6和4.6的更新。

关于应用程序域,我个人认为我可以卸载卸载程序集的应用程序域。如果一个程序集被卸载,它就会消失,而IL代码也会随之而来。我认为保留被破坏的IL代码的本机代码没有多大好处。因此,我可以想象创建一个应用程序域并再次加载程序集可能会导致再次JIT该方法。

关于代码访问安全性,我不确定JIT编译器是否基于当前权限考虑它是否由运行时的反射完成。如果由JIT编译器完成,则编译的代码将有所不同,具体取决于权限集。

1 个答案:

答案 0 :(得分:2)

"设计原则" JIT的一个方法是编译一个方法(泛型方法的方法实例化),并重用相同的本机代码。当然,实现非常复杂,我会尝试简化答案而不影响准确性。从.NET 2.0到最新的.NET 4.6,所有运行时版本的答案都是一样的(我不了解.NET 1.x,可能是相同的)。

运行时分析器回调和ETW事件的记录很少。它们都在尝试JIT编译时发生,但不一定成功。有三种情况会发生这种情况:1-方法无法满足某些安全要求,2-方法验证失败,无法分配3个内存来保存本机代码。因此,JIT启动回调和事件可能会高估实际编译方法的次数。同样,JIT完成回调和事件也不准确。很少发生的案例可能会低估同一方法成功编译的次数。值得一提的是,# of Methods JITted performance counter准确报告了所有IL方法在流程的所有appdomains中集体编译的次数。

对于特定于appdomain的程序集,方法将在每个appdomain中单独编译。没有共享(尽管有时可能在技术上可行)。对于appdomain-neutral程序集,运行时尝试编译每个方法一次,并与所有appdomains共享本机代码。

  

如何证明.NET CLR JIT每次只编译一次方法   运行

好吧,在某些情况下(比如使用后台JIT和其他非常微妙的情况),一个方法可以编译而不会被执行。所以说每次运行一次编译每个方法是不准确的。

您可以参考CoreCLR JIT源代码以获取更多信息(JIT与.NET framework 4.5+中使用的相同,但此答案适用于旧版本,因为JIT触发机制大致相同)。源代码就是证据。

  每个线程的每个对象都有

方法

是的,这没有任何意义。编译范围是appdomains。