不存储引用时 .maxstack 更大吗?
我不是任何类型的 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?为什么第二个代码会导致系统为该操作保留更大的堆栈?
I am no IL master of any sort, I just use it sometimes to check what the compiler makes of the code that I write. One thing that I have been wondering about is why .maxstack
gets the value it gets sometimes. Consider the following class:
public class Sample
{
public void SomeMethod(){}
}
Then, I have a program like this:
private static void Main(string[] args)
{
Sample sample = new Sample();
sample.SomeMethod();
}
The above code gives the following IL (Release compiled):
.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
Now, if I change the program code into this:
private static void Main(string[] args)
{
new Sample().SomeMethod();
}
...it results in the following IL code:
.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
The second IL code is shorter, which was expected. But what gets me a bit curious is why .maxstack
i 8 in the second code sample, but 1 in the first? Why does the second code lead to the system reserving a larger stack for the operation?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
方法头的二进制表示有“tiny 格式”和“fat 格式”。 Tiny header 占用的字节数较少,只要满足以下条件就可以使用:
您的更改允许编译器使用此形式,并且当遇到小标头时,始终假定使用最大堆栈为 8。
参考是 ECMA-335 §25.4.2
旁注 我特别感兴趣的是以下事实:发布版本(根据您在OP中的注释)他们生成了不同的代码,其中缩短的形式既更小又更快。您使用什么版本的 C#?我希望以后的版本能够利用这种明显的优化:
Sample
,因此即使SomeMethod
是虚拟的,它也可以直接使用调用它>调用
指令。The binary representation of a method header has a "tiny format" and a "fat format". The tiny header takes fewer bytes and can be used as long as the following conditions are met:
Your change allowed the compiler to use this form, and when a tiny header is encountered it is always assumed to use a max stack of 8.
Reference is ECMA-335 §25.4.2
On a side note Of particular interest to me is the fact that in a release build (per your note in the OP) they produced different code, where the shortened form is both smaller and faster. What version of C# are you using? I would expect later versions to take advantage of this obvious optimization:
Sample
, so even thoughSomeMethod
is virtual it can call it directly with thecall
instruction.