很久以前,我想知道变量(值类型或引用类型)将存储在哪里。它会在堆栈还是堆上?
我也读过Eric Lippert 的文章。
出于好奇,我想要交叉验证我所理解的内容。任何工具都存在吗?或者我会以任何方式知道,在执行 .NET 程序时,哪些变量会存储在堆栈中?哪个存储在堆上?
谢谢
很久以前,我想知道变量(值类型或引用类型)将存储在哪里。它会在堆栈还是堆上?
我也读过Eric Lippert 的文章。
出于好奇,我想要交叉验证我所理解的内容。任何工具都存在吗?或者我会以任何方式知道,在执行 .NET 程序时,哪些变量会存储在堆栈中?哪个存储在堆上?
谢谢
考虑按堆栈和堆划分存储是一种方便的抽象,可以很好地为您服务。但更复杂的是,.NET 程序中有 6 个不同的变量存储位置。
这里选择的工具是调试器,它可以准确地显示变量存储的位置。这确实需要深入了解机器代码的工作原理。使用 Debug + Windows + Disassembly 查看机器码。查看程序的发布版本并更改允许即使在调试代码时也能优化代码的设置也很重要。工具 + 选项,调试,常规,取消勾选“在模块加载时抑制 JIT 优化”选项。您现在将看到机器代码在您的用户机器上执行的方式。
你必须事先知道的事情才能理解这一切:
引用类型的对象存储在 GC 堆上。存储引用的变量具有与值类型值相同的存储选择。
值类型值或对象引用有六个可能的存储位置:
后三个要点是它变得复杂的地方,以及为什么您需要查看机器代码来找出它们的存储位置。它是高度实现特定的,抖动的类型很重要。并且受您是否启用抖动优化器的影响很大。在这里做出正确的选择对性能非常重要。粗略的轮廓(跳过 ARM 抖动):
前两个方法参数存储在 x86 抖动的 CPU 寄存器中,包括实例方法的this的值。x64 抖动使用 4 个寄存器。浮点处理器寄存器用于在 x86 上传递 Single 和 Double 类型的变量,在 x64 上传递 XMM 寄存器
函数返回值在 CPU 寄存器中返回,如果它适合,则使用 EAX 或 RAX 寄存器,如果它是浮点值,则返回 ST0。如果它不适合,则调用者在堆栈帧上为该值保留空间并传递一个指向它的指针
抖动优化器寻找机会将局部变量存储在 CPU 寄存器中。如果由于寄存器用完而被迫这样做,它可能会将寄存器溢出回堆栈帧。
这些实现细节有许多可观察到的副作用: