我无法在SO或互联网上找到类似的问题/答案,而且这个问题也没用,这可能是我在MSIL上阅读时遇到的一个问题。我非常想知道在我的场景中IL操作执行是如何工作的,即使这不是一个我没有其他人要问的实际问题。
前提:
请记住,MSIL命令和函数的执行分三步完成:
步骤1和3是可选的。例如,void函数不会将返回值推送到堆栈。
我知道这是一种方法可以决定需要多少“处理能力”,但为了我的好奇心,我们可以考虑这两种非常基本的方法:
第一种方法:
void Method1()
{
var result = 1+1;
}
第二种方法:
int Method2()
{
var result = 1+1;
return result;
}
问题:
因为void方法没有推送返回值(或者是否存在隐式返回)这是否意味着在执行时需要较少的开销而不是第二种方法?
答案 0 :(得分:6)
但请记住,MSIL不会被执行甚至解释。 MSIL是已编译代码的表达式,因为它将在虚拟机上执行。但是JIT编译器将MSIL转换为机器代码(x86等)。 x86与基于堆栈的虚拟机根本不同。
在最基本的级别,函数返回寄存器中的值。假设寄存器足够大。让我们坚持使用64位值(引用,长整数,双精度和较小值类型)。这些可以在RAX寄存器中返回。在您的简单示例中,两个函数的生成机器代码没有区别。也就是说,Method1
将是:
mov rax, 1
inc rax
ret
(并且,是的,我知道智能编译器会将1+1
折叠为2
。让我们假设那里有内存访问,好吗?)
Method2
将是相同的,因为要返回的值已经在RAX寄存器中。
因此,当您使用64位或更小的数量时,返回值的方法与不返回值的方法之间的差异通常会有所不同,如果有的话,只会在它所需的任何指令中将返回值加载到适当的寄存器中。这通常是单mov
条指令。这将取决于事情的完成顺序,以及编译器和JITer如何优化事物。
答案 1 :(得分:3)
所有事情都是平等的,做某事比做某事慢。
但请注意,第一种方法的实现将转变为:
void Method1()
{
}
内联之后,甚至没有调用它(如果这是另一个对象的实例方法,那么调用可能被读取字段替换,因为优化不能阻止{{1如果它是null,那么它应该抛出。如果它是静态的,从同一个对象调用,或者编译器确定该对象不能为null,那么甚至不是。零代码。
同时,第二种方法将转变为:
NullReferenceException()
内联后,使用该值的调用将从例如:
转为int Method2()
{
return 2;
}
要:
x = Method2();
如果没有使用该值,那么即使没有;它与第一个完全一样。
这种事情正在发生意味着即使在没有内联呼叫的情况下,诸如是否返回某些内容之类的微小差异将大部分丢失,因为即使对更大的因素没有噪声也会丢失,并且也可能发生反...直观地(通过影响是否以某种模糊的方式采用某些优化路径)。示例:生成值,通过将其放入寄存器中“返回”,但也许它在计算时仍然存在,也许它的下一个用途直接在那里工作;因此“返回”它的成本为零。