我不是任何类型的IL大师,我有时会用它来检查编译器对我编写的代码的作用。我一直想知道的一件事是为什么.maxstack
有时获得它所获得的价值。考虑以下课程:
public class Sample
{
public void SomeMethod(){}
}
然后,我有一个这样的程序:
private static void Main(string[] args)
{
Sample sample = new Sample();
sample.SomeMethod();
}
上面的代码给出了以下IL(发布版本):
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 13 (0xd)
.maxstack 1
.locals init ([0] class ConsoleApplication1.Sample sample)
IL_0000: newobj instance void ConsoleApplication1.Sample::.ctor()
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: callvirt instance void ConsoleApplication1.Sample::SomeMethod()
IL_000c: ret
} // end of method Program::Main
现在,如果我将程序代码更改为:
private static void Main(string[] args)
{
new Sample().SomeMethod();
}
...它产生以下IL代码:
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 11 (0xb)
.maxstack 8
IL_0000: newobj instance void ConsoleApplication1.Sample::.ctor()
IL_0005: call instance void ConsoleApplication1.Sample::SomeMethod()
IL_000a: ret
} // end of method Program::Main
第二个IL代码更短,这是预期的。但让我有点好奇的是为什么.maxstack
i 8在第二个代码示例中,但是第一个代码中的1?为什么第二个代码会导致系统为操作保留更大的堆栈?
答案 0 :(得分:4)
方法标题的二进制表示具有“小格式”和“胖格式”。微小的标头占用的字节更少,只要满足以下条件就可以使用:
您的更改允许编译器使用此表单,当遇到小标题时,始终假定使用最大堆栈8。
旁注我特别感兴趣的是,在发布版本中(根据OP中的说明),他们生成了不同的代码,其中缩短的形式既小又快。您使用的是哪个版本的C#?我希望以后的版本能够利用这种明显的优化:
Sample
,所以即使SomeMethod
是虚拟的,它也可以直接用call
来调用它。指令。