为何C#编译器不对MSIL代码进行内联优化?
这个问题问到点子上了——咱们都清楚JIT在生成X86汇编时会做内联,但为啥C#编译器不在MSIL层面干这件事?核心原因主要有这几点:
MSIL内联的实际收益几乎可以忽略
MSIL只是中间语言,不是最终跑在CPU上的机器码。就算在MSIL层面把函数内联了,最终还是要靠JIT把这些膨胀后的MSIL转成机器码。而且JIT本身就有一套成熟的内联逻辑,它能根据目标CPU架构、当前运行环境(比如CPU支持的指令集)做更精准的优化。反而MSIL内联会让程序集体积变大,增加加载和JIT编译的时间,完全得不偿失。JIT拥有更多优化上下文信息
静态编译MSIL的时候,C#编译器不知道很多关键信息:比如函数的实际调用频率、泛型方法的具体类型参数、甚至是运行时的内存布局。而JIT是在程序运行时做优化,它能拿到这些实时信息——比如某个函数被调用了成千上万次,JIT就会优先把它内联;对于泛型方法,JIT能针对具体的类型生成最优的机器码,这时候内联才能真正提升性能。如果C#编译器在MSIL层面强行内联,反而会限制JIT的优化空间。.NET编译模型的分工设计
.NET从一开始就采用了“两次编译”的思路:C#编译器的职责是把C#代码转换成语义正确、结构清晰的MSIL,保证代码的可读性和可维护性;而性能优化的重担则交给JIT(或者现在的Native AOT)编译器。这种分工让每个环节都能专注于自己的领域,C#编译器不用去处理复杂的平台相关优化逻辑,JIT则可以全力针对目标硬件做极致优化。实现成本远大于收益
要在C#编译器里实现MSIL内联,得额外开发一套复杂的分析逻辑:比如判断哪些函数适合内联(不能是虚方法、不能有递归、不能有副作用等等)、处理各种边界情况,还要考虑调试体验(内联后调试时的栈帧会更复杂)。但做了这些工作之后,实际能带来的性能提升几乎可以忽略——毕竟最终的性能还是由JIT生成的机器码决定的。所以从投入产出比来看,这个功能从来就没被提上实现日程。
内容的提问来源于stack exchange,提问作者rollsch

