C# IL代码中maxstack值的计算
我有下面的程序来添加这些值。 当我在main方法中调用Add方法并查看ILDASM.EXE时,Maxstack大小为2。取消注释后,maxstack大小变为4 为什么在主方法的情况下,所有变量都没有进入堆栈,因为堆栈大小仅为2,而在Add方法调用的情况下,每个变量都进入堆栈? 在这种情况下,主方法内部的计算是一个接一个地进行的,因此一次只需要两个变量 请澄清我的困惑C# IL代码中maxstack值的计算,c#,stack,cil,il,ildasm,C#,Stack,Cil,Il,Ildasm,我有下面的程序来添加这些值。 当我在main方法中调用Add方法并查看ILDASM.EXE时,Maxstack大小为2。取消注释后,maxstack大小变为4 为什么在主方法的情况下,所有变量都没有进入堆栈,因为堆栈大小仅为2,而在Add方法调用的情况下,每个变量都进入堆栈? 在这种情况下,主方法内部的计算是一个接一个地进行的,因此一次只需要两个变量 请澄清我的困惑 static void Main(string[] args) { int x = 2; int y = 3;
static void Main(string[] args)
{
int x = 2;
int y = 3;
int a = 4;
int b = 5;
int c = 6;
Console.WriteLine(x + y + a + b + c);
Console.WriteLine(Add(10, 20, 30, 40));
Console.ReadLine();
}
static int Add(int x, int y, int z, int a)
{
return x + y + z + a;
}
每个变量初始化:
int x = 2;
将要求值位于堆栈上:(堆栈大小:到目前为止需要1)
这些操作按顺序进行,因此在以下期间,所需的最大堆栈大小仍然为1:
int y = 3;
int a = 4;
int b = 5;
int c = 6;
说到这里:
Console.WriteLine(x + y + a + b + c);
要添加任意两个变量,堆栈大小必须为2:
IL_000b: ldloc.0 // copy to stack x, max stack size required is still 1.
IL_000c: ldloc.1 // copy to stack y, max stack size required is 2 now.
IL_000d: add // execute add, will cause the sum x + y to be on stack
IL_000e: ldloc.2 // copy to stack a
IL_000f: add // execute add... (adds a to the result of x + y)
....
下面是取消注释Add方法时的差异IL
调用方法时,需要将实例引用推送到堆栈上(这意味着,如果Add方法是非静态的,那么指向其声明类型的实例指针应该推送到堆栈上)
然后,需要传递给方法的每个参数也应该推送到堆栈上
因此,在您的案例中,定义最大堆栈大小的是Add方法的参数数量。将参数添加到此Add方法中,您将看到最大堆栈大小将增加到5:
// method is static so no need to push an instance pointer to the stack
IL_001a: ldc.i4.s 10 // push to stack
IL_001c: ldc.i4.s 20 // push to stack
IL_001e: ldc.i4.s 30 // push to stack
IL_0020: ldc.i4.s 40 // push to stack
IL_0022: call int32 Program::Add(int32,
int32,
int32,
int32)
IL_0027: call void [mscorlib]System.Console::WriteLine(int32)
我会稍微调整顶部的措辞-不是声明使用堆栈空间,而是初始化。@Damien_不信者感谢您的审阅和更正。修正它。就像IL不是逐行生成的一样。我的意思是,当x=2接受一个堆栈空间时,为什么不进行其他值声明呢?这是否就像编译器知道它只需要加法,所以堆栈中的2个空间就足够了。@TBAG-
x=2
需要一个堆栈空间-它将2
推到堆栈上,然后将其从堆栈中弹出到变量x
中。在这一点上,堆栈再次是空的。内联一个方法体的好处将是大量的IL指令,这主要取决于该方法具有的参数数量。如上所述,调用带有4个参数的静态方法需要5条IL指令。编译器足够聪明,可以在必要时内联内容。不要因此而破坏模块化。
// method is static so no need to push an instance pointer to the stack
IL_001a: ldc.i4.s 10 // push to stack
IL_001c: ldc.i4.s 20 // push to stack
IL_001e: ldc.i4.s 30 // push to stack
IL_0020: ldc.i4.s 40 // push to stack
IL_0022: call int32 Program::Add(int32,
int32,
int32,
int32)
IL_0027: call void [mscorlib]System.Console::WriteLine(int32)