c# - 堆栈 - 值类型的值存储在哪里?

标签 c# memory-management stack

void main()
{
    int x = 5; // stack-allocated
    Console.WriteLine(x);
}

我知道 x 是堆栈分配的。但是关于 x 的堆栈中实际上存储了什么?它保存的是“实际值”,还是包含该值的内存中某个位置的地址?

最佳答案

答案是响亮的“视情况而定”。

有一件事是肯定的:局部变量 x 的存储,如果它存在的话,包含一个实际值而不是一个引用,因为 int 是一个值类型。

在简洁的脑死亡翻译中,x 的实际值(不是指针或指向它的引用)存储在当前调用的激活记录中的局部变量中。生成的 IL 将是这样的:

  .maxstack 1
  .locals init (int32 V_0)

  ldc.i4.5  // push 5 on the evaluation stack
  stloc.0   // pop it into x

  ldloc.0   // now push a copy of x to pass to ...
  call void [mscorlib]System.Console::WriteLine(int32)

  ret       // return

(请注意,.maxstack 指令谈论的是 IL 评估堆栈,不一定对应于 native 堆栈。如果评估堆栈较浅,则通常由 JIT 编译代码保存在寄存器中.)

在 CLR 的大多数当前实现中,激活记录及其局部变量将存储在 native 堆栈中。所以,我天真地认为 x 可以被认为是将其值存储在堆栈中。

在上述代码的优化编译(或优化 JIT 翻译)中,IL 中可能根本不存在局部变量存储。毕竟,为什么要分配局部变量存储来存储它,然后浪费两条指令来处理该局部变量,而您再也不需要它了?它可以作为 WriteLine 的常量参数内联:

  .maxstack 1
  // Just pass 5 to WriteLine.  No local variables here.
  ldc.i4.5
  call void [mscorlib]System.Console::WriteLine(int32)
  // Bye.
  ret

还有更多可能的并发症。如果函数在 C# 5 CTP 中被声明为 async,或者如果 x 被函数中其他地方的 lambda 表达式捕获,或者如果函数是使用yield return 语句,x 的存储最终可能会被强制放到堆上:它将成为编译器生成的类中的一个字段,这样变量的存储就可以在撕裂后继续存在- 如果闭包或延续超出局部作用域,则栈帧向下。

关于c# - 堆栈 - 值类型的值存储在哪里?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7684108/

相关文章:

c# - XmlDocument 存在于哪个程序集中,以及如何使用它?

c# - 如何在asp.net C# 中单击按钮后启动倒计时器?

c# - List.Add 未完美添加并行和异步

iPhone:对象保留其委托(delegate)是否有意义?

c++ - 通过引用传递数据成员

c# - SortedList of Lists 中最长的列表

objective-c - 核心数据故障和内存警告

c - 分配内存中的空白空间会发生什么?

堆栈对象的 C++ 继承

c - 归并排序和递归