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

标签 c# .net clr windbg jit

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

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

我目前的研究

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

为什么我对说法的正确性存疑?

我们举办了一个并行编程研讨会,培训师声称方法是针对每个线程的每个对象进行 JIT 处理的。这对我来说显然没有意义,我能够编写一个反例应用程序。

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

  • 新的 .NET 框架
  • 应用领域
  • 代码访问安全

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

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

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

最佳答案

JIT 的“设计原则”是编译一个方法(泛型方法的实例化)一次,然后重用相同的本地代码。当然,实现起来非常复杂,我会尽量在不影响准确性的情况下简化答案。对于从 .NET 2.0 到最新的 .NET 4.6 的所有版本的运行时,答案都是相同的(我不知道 .NET 1.x,可能是相同的)。

运行时分析器回调和 ETW 事件的文档很少。当尝试进行 JIT 编译但不一定成功时,它们都会发生。在三种情况下可能会发生这种情况:1- 方法无法满足某些安全要求,2- 方法验证失败,以及 3- 无法分配内存来保存要发出的 native 代码。因此,JIT 启动回调和事件可能会高估方法实际编译的次数。同样,JIT 完成回调和事件也不准确。在极少数情况下,他们可能会低估同一方法已成功编译的次数。在这一点上值得一提的是 # of Methods JITted performance counter准确报告所有 IL 方法在一个进程的所有应用程序域中被集中编译的次数。

对于特定于应用程序域的程序集,方法在每个应用程序域中单独编译。没有共享(尽管有时在技术上是可行的)。对于与应用域无关的程序集,运行时尝试编译每个方法一次并与所有应用域共享 native 代码。

How to prove that the .NET CLR JIT compiles every method only once per run?

嗯,在某些情况下(例如使用后台 JIT 和其他极其微妙的情况),一个方法可以在不执行的情况下编译。所以说每个方法每次运行编译一次是不准确的。

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

methods are JITted for every object per thread

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

关于c# - 如何证明 .NET CLR JIT 每次运行只编译每个方法一次?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42262201/

相关文章:

c# - 后台线程循环和双向通信

c# - 将逻辑调用上下文从 OWIN 管道传递到 WebApi Controller

c# - IIDentity 不包含 'GetUserId' 的定义

c# - WPF中分段进度条的一些快速简单的实现是什么?

.net - .NET 中的数组是否自然对齐?

c# - Azure功能Skype机器人输出绑定(bind)

c# - 自动更新 : Is this secure?

c# - 调试 WP7 崩溃

memory-management - WinRT 如何处理 BitmapImage 和 Image 内存

.net - 为什么 PEVerify 说 CLR 期待静态大小数组的单维数组?