C#程序运行时会先将源代码编译为中间语言IL,之后在程序执行过程中由JIT编译器将IL转换为对应平台的机器码,分层编译Tiered Compilation是.NET运行时为提升JIT编译效率和程序运行性能引入的机制,它改变了传统JIT一次性编译所有方法的模式。

什么是分层编译Tiered Compilation
分层编译是.NET Core 3.0及之后版本默认开启的JIT编译特性,核心思路是根据方法的执行频率和热度,分不同层级对方法进行编译,平衡编译速度和运行性能。传统JIT编译模式下,所有方法第一次被调用时就会被编译为优化程度较高的机器码,这会导致程序启动阶段需要消耗大量时间在编译上,拖慢启动速度。
分层编译将方法的编译过程分为多个层级,不同层级的编译速度和优化程度不同,运行时可以根据方法的实际执行情况动态切换编译层级,既保证程序启动速度,又能在方法频繁执行时获得更高的运行性能。
分层编译的核心层级
分层编译主要包含以下三个核心编译层级:
- 层级0:快速编译:方法第一次被调用时触发,编译速度极快,几乎不做任何优化,目的是让方法尽快可以执行,减少程序启动阶段的编译耗时。
- 层级1:优化编译:当方法被判定为热点方法,也就是执行次数达到一定阈值后,会触发层级1的编译,此时JIT会做较多的优化,生成性能更高的机器码,替换原来的层级0机器码。
- 层级2:完全优化编译:部分场景下,对于执行频率极高的核心方法,会进一步触发层级2编译,JIT会做更激进的优化,比如更彻底的内联、循环优化等,进一步提升运行性能。
C# JIT借助分层编译优化代码的流程
JIT编译器在分层编译机制下,会按照固定的流程完成代码优化,整个过程对开发者透明,不需要手动干预。
1. 初始快速编译阶段
当程序第一次调用某个方法时,运行时首先会检查该方法是否已经有编译好的机器码,如果没有,就会触发层级0的快速编译。这个阶段的JIT编译逻辑非常简单,只是将IL转换为基础的机器码,不会做任何复杂的优化,编译耗时极短。
我们可以通过简单的C#代码观察方法的第一次执行,示例代码如下:
using System;
class Program
{
static void Main()
{
// 第一次调用Test方法,触发层级0快速编译
Test();
// 多次调用Test方法,触发更高层级的优化编译
for (int i = 0; i < 10000; i++)
{
Test();
}
}
static int Test()
{
int a = 10;
int b = 20;
return a + b;
}
}
2. 热点方法检测与层级升级
运行时会在后台统计每个方法的执行次数,当某个方法的执行次数超过预设的阈值时,就会被标记为热点方法。此时运行时会触发该方法的更高层级编译,JIT会重新将IL转换为优化程度更高的机器码。
JIT在优化编译阶段会做多种优化,比如方法内联,对于上面示例中的Test方法,因为逻辑非常简单,JIT很可能会将Test方法的代码直接内联到Main方法中,避免方法调用的开销。内联优化后的代码逻辑类似下面这样:
static void Main()
{
// 内联后的Test方法逻辑
int a = 10;
int b = 20;
int result = a + b;
// 多次执行内联后的逻辑
for (int i = 0; i < 10000; i++)
{
a = 10;
b = 20;
result = a + b;
}
}
3. 动态优化调整
分层编译还支持动态去优化,也就是如果某个之前被判定为热点的方法,后续执行频率降低,运行时也可以将其切换回低层级编译的机器码,减少内存占用。同时如果程序运行过程中加载了新的类型,导致之前的优化假设不成立,JIT也会重新编译方法,保证优化的正确性。
分层编译相关的配置与查看
分层编译默认是开启的,我们也可以通过配置来关闭或者调整相关参数。在.NET应用中,可以在项目文件或者运行时配置中设置相关选项:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<!-- 关闭分层编译 -->
<TieredCompilation>false</TieredCompilation>
</PropertyGroup>
</Project>
如果需要查看JIT的编译过程和优化细节,可以使用.NET提供的诊断工具,比如dotnet-trace或者PerfView,这些工具可以记录方法的编译层级切换、执行次数等信息,帮助开发者分析JIT优化是否符合预期。
分层编译的优势与适用场景
分层编译最大的优势是平衡了程序启动性能和运行性能,对于启动速度要求高的应用,比如桌面应用、Web API服务,分层编译可以明显减少启动阶段的编译耗时,同时保证高频执行的方法获得足够的优化。
几乎所有C#应用场景都适合开启分层编译,尤其是那些包含大量短期执行方法和少量核心热点方法的应用,分层编译的优势会更加明显。只有在极少数对编译行为有严格固定要求的特殊场景下,才需要考虑关闭分层编译。
Tiered_CompilationJIT分层编译代码优化C#修改时间:2026-07-07 15:21:26