为什么C#会提前绑定局部变量

本文关键字:绑定 局部变量 为什么 | 更新日期: 2023-09-27 18:22:06

因此,在C#中,您可能有以下代码:

void DoSomething()
{
    //some code.
    int x = 5;
    //some more code.
}

一旦输入DoSomething,CLR就会为int x设置空间。为什么它不等到到达int x=5的行?特别是因为即使x是有界的,它也不会让你真正使用它,直到到达那条线?

为什么C#会提前绑定局部变量

一旦输入DoSomething,CLR就会为int x设置空间。为什么它不等到它到达上面有int x = 5的线路?

这个问题无法回答,因为整个问题是建立在一个错误的前提下的。本地变量的存储空间可以是:

  • 首次输入方法时分配
  • 在控制到达声明时分配
  • 当控件达到初始化时分配(假设初始化和声明不同)
  • 在特殊情况下分配——例如,如果local是lambda的闭上local,或者在迭代器块中,或者在异步块中,如何以及何时分配本地存储可能会变得复杂
  • 完全消失;如果从未使用过local,那么它可能一开始就不会被分配

C#编译器和jit编译器肯定会确保以正确的方式分配本地存储,并尝试确保其高效。他们如何选择这样做取决于具体情况。提前分配空间可能更有效,并且只在变量使用期间分配空间可能更有效率;在选择局部变量的寿命时,抖动是允许的。如果抖动可以在不违反程序正确性的情况下实现,则允许局部变量的生存时间比其作用域所暗示的更长和更短。

由于这个问题的前提是不正确的,所以这个问题没有答案。问一个更好的问题。

正如您所知,从C#代码到本机代码有几个步骤,它们是:

  • 从C#编译到IL(字节码)
  • 从字节码到本机代码的JITting

C#无法控制分配内存的时间,也就是您所说的绑定,这完全取决于JIT。解决这个问题,让我们看看在C#的控制中是什么。C#生成的字节码必须遵守CLR ECMA标准。如果我们转到分区1的12.1.6.1节,我们会看到,标准定义局部变量的home是方法头中的。由于方法签名通常会出现在列表中方法的开头,因此您会得到一种(错误的)印象,即它们预先绑定了,事实上可能是,也可能不是。

然而,如果您查看编译后的本机代码,结果可能因平台而异。从历史上看,在CPU堆栈上为局部变量分配空间是通过改变堆栈指针的单个CPU指令来完成的。如果你想逐个变量地执行,那么你会有多条指令,每个变量一条,这效率较低。这就是为什么,至少在x86上,您会看到CPU堆栈上的空间是预先分配的。

如果编译器发现类似的内容,该怎么办

 for (int i = 0; i < 1000; i++)
 {
     int j = .... //should the compiler set up space when it reaches this line? 1000 times?
 }

此外,我真的认为建立当地人空间的成本不是一个因素。如果真的是这样,那么你可能在一个方法中处理了太多的局部变量,你最好重构你的代码。

您的问题似乎基于以下几个假设:

  • 安装成本总是很高
  • 安装程序只会发生少量
  • CLR级别的引用/值类型总是与C#级别的变量进行一对一映射

这些可能适用于您的代码,但可能不适用于大多数代码。

这些假设似乎也忽略了编译/解释机器代码的过程中底层的存在。

简而言之,您在C#中编写的代码是一个依赖于IL的抽象,IL是另一个依赖CLR的抽象,CLR是另一种抽象,依此类推

就其价值而言,我非常怀疑这个决定是否会对您的应用程序的性能产生重大影响。。。但也许像埃里克·利珀特(http://blogs.msdn.com/b/ericlippert/)可以分享更深入的分析。