我是编程新手,这给我带来了很多困惑。
假设我们有以下声明:
Int32 i = 1;
i
的内容存储在内存中,这将是四个字节:00000000 00000000 00000000 00000001
CLR如何在以后访问此内存位置? CLR是否将地址存储在某个内存块中?
答案 0 :(得分:4)
System.Int32
是值类型,未使用任何引用。
实际上,如果编译器可以找到一个CPU寄存器来保存它,那么局部变量可能永远不会在内存中。
如果它在内存中,它的地址将通过向堆栈指针(ESP
)或包含引用类型(C#中的class
)对象的地址添加一个偏移量来找到它
在从JIT生成的代码中,值类型的变量与本机代码使用的变量无法区分(没有对象头或类似的东西)。
答案 1 :(得分:3)
编译器会跟踪变量的位置,以便它可以创建以正确方式访问变量的代码。
在这种情况下,您将声明一个局部变量,因此它将在堆栈上分配。
程序不会访问特定地址的变量,而是访问基指针的偏移量,该指针指向当前方法的堆栈帧。
将变量设置为1的代码在编译为32位应用程序的机器代码时可以看起来像这样:
mov dword ptr [ebp-8],1
ebp
寄存器指向堆栈帧的顶部,因此i
变量在此情况下分配了8个字节。
答案 2 :(得分:2)
假设NORMALLY,如果i
是局部变量,它将保存在堆栈中。 .NET的抽象 VM是基于堆栈的。
我要补充一点,在Intel / AMD上i
将不会以这样的方式保存:-) Intel / AMD little endian 。所以它将是00000001 00000000 00000000 00000000
我正在混合它......现在...... IL语言和.NET 抽象 VM基于“纯”堆栈,所以有一个堆栈:-)(但是没有寄存器,所以“纯粹”(我希望你知道什么是堆栈)。当代码被JIT打印到您正在使用的计算机的机器代码时,可能i
将被放入寄存器或堆栈中。
请注意一般,如果要将值类型(或非引用类型,如果要包含托管/非托管指针/引用)保存在堆栈和/或上,那么错误是错误的错误在寄存器中。它们被保存在保存的地方。例如,类的值类型成员与(in)类一起保存(因此堆中的通常)。 yield函数,异步函数,“普通”方法中的值类型,但被“闭包类型”匿名函数引用,通常保存在堆中的某处。但所有这些都是参考实现细节。
答案 3 :(得分:0)
从我所知道的,实际的堆分配引用存储为双指针(或一些等价物),以便垃圾收集器可以移动内存,而不必影响代码中的任何地方,通过更新指针指向来引用某些内容。 / p>