CLR -存储引用地址的地方
本文关键字:地址 引用 存储 CLR | 更新日期: 2023-09-27 18:12:42
我是一个编程新手,这给我带来了很多困惑。
假设我们有以下语句:
Int32 i = 1;
i
的内容存储在内存中,内存为4个字节:00000000 00000000 00000000 00000001
CLR以后如何访问这个内存位置?CLR是否将地址存储到这个内存块的某个地方?
System.Int32
是一个值类型,没有引用。
事实上,如果编译器能找到一个CPU寄存器在局部变量的整个生命周期中保存它,那么局部变量可能永远不会在内存中。
如果它在内存中,它的地址将通过在堆栈指针(ESP
)或包含它的引用类型(c#中的class
)对象的地址上添加偏移量来找到。
在JIT生成的代码中,值类型的变量与本机代码使用的变量是无法区分的(没有对象头或类似的东西)。
编译器跟踪变量的位置,以便它可以创建以正确方式访问它的代码。
在这种情况下,你声明了一个局部变量,所以它将在堆栈上分配。
程序不会访问特定地址的变量,而是作为基指针的偏移量访问,基指针指向当前方法的堆栈帧。
例如,将变量设置为1的代码在编译为32位应用程序的机器码时看起来像这样:mov dword ptr [ebp-8],1
ebp
寄存器指向堆栈帧的顶部,因此在本例中i
变量被分配到比它低8个字节的位置。
假设正常情况下,如果i
是一个局部变量,它将被保存在堆栈上。. net的抽象虚拟机是基于堆栈的虚拟机。
我要补充的是,在英特尔/AMD i
不会这样保存:-)英特尔/AMD是小尾端。所以改成00000001 00000000 00000000 00000000
我把它混合了一点…现在…IL语言和。net 抽象 VM是"纯"基于堆栈的,所以有一个堆栈:-)(但没有寄存器,所以"纯")(我希望你知道堆栈是什么)。当代码被编译为您正在使用的计算机的机器码时,i
可能会被放入寄存器或堆栈中。
注意一般来说说值类型(或者非引用类型,如果你想包含托管/非托管指针/引用)保存在堆栈和/或寄存器中是错误的。他们被拯救在他们被拯救的地方。例如,类的值类型成员被保存在类中(因此通常在堆中)。yield函数、异步函数、"普通"方法中的值类型,但被"闭包类型"匿名函数引用时,通常保存在堆的某个地方。但是这些都是参考实现细节
据我所知,实际的堆分配引用被存储为双指针(或一些等效的),以便垃圾收集器可以移动内存,而不必通过更新指向的指针来影响代码中引用的任何地方。