在C#中,您可能会有以下代码:
void DoSomething()
{
//some code.
int x = 5;
//some more code.
}
一进入DoSomething,CLR就会为整数x设置空间。为什么它不等到int x = 5这行代码执行时才分配空间呢?特别是因为即使x被绑定了,它也不会让你在到达那行代码之前使用它。
DoSomething
方法,CLR就会为int x
分配空间。为什么它不等到达带有int x = 5
的那一行再分配呢?正如你所知,从C#代码到本地代码的步骤有几个:
C#不能控制内存分配时间(称为binding),这完全由JIT决定。让我们看看C#能控制什么。C#产生的字节码必须遵循CLR ECMA标准。如果我们进入第一部分的12.1.6.1部分,我们会看到,该标准定义了局部变量的位置在方法头中。由于方法签名通常出现在列表中的开头,因此您会得出一个(错误的)印象,即它们是提前绑定的,而实际上可能是也可能不是。
但是,如果您查看编译后的本地代码,结果可能因平台而异。从历史上看,为本地变量在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?
}
你的问题似乎基于一些假设:
这些可能对你的代码是正确的,但对大多数代码来说可能不成立。
这些假设还似乎忽略了编译/解释此过程的底层层次的存在,将其转换为机器代码。
简而言之,在C#中编写的代码是一个抽象,它依赖于另一个抽象IL,后者依赖于CLR,依此类推。
就我个人而言,我严重怀疑这个决定是否会对您的应用程序性能产生重大影响...但也许像Eric Lippert(http://blogs.msdn.com/b/ericlippert/)这样的人可以分享更深入的分析。
esp
)-- 直到遇到new
才会进行“分配”,这里所做的一切都是为了保留堆栈空间。 - ildjarn