【问题标题】:When are value types stored in stack(C#)?值类型何时存储在堆栈(C#)中?
【发布时间】:2013-08-24 22:02:12
【问题描述】:

当我阅读下一本书“值和引用类型”一章时,我想到了一个问题:“值类型何时存储在堆栈中”?原因程序员无法在类外初始化任何值类型。因为当我们在类中初始化一些值类型的变量时,变量存储在堆中。

我的问题是:值类型何时存储在堆栈中?

【问题讨论】:

  • 你应该再读一遍这一章。我敢肯定它在某处得到了彻底的解释。
  • 您需要知道的就是这个问题。一些非常好的答案。 stackoverflow.com/questions/4487289/…
  • 附带说明,我看过很多书弄错了。我还看到很多书错误地描述了值类型和引用类型之间的区别。所以完全有可能这里的错不是你,而是这本书。我实际上是一本在这里犯了一些错误的书的技术编辑;我一再指出错误,但没有得到纠正——所以我不得不要求从书中删除我的名字(我不是为了给它盖上橡皮图章!)

标签: c#


【解决方案1】:

嗯,首先,您很少需要知道,但基本上,值类型存储在它们所拥有的任何地方

当它们是线程执行流程的一部分时,它们被存储在堆栈中,这可能意味着:

  • 在“本地”(方法变量)中 - 不包括某些情况(如下)
  • 作为方法的一部分中的浮点值,即将作为值传递给另一个方法的一个方法的返回值 - 不涉及“本地”,但该值仍在堆栈中
    • 按值传递的值类型参数(即没有refout)只是这种情况的一个特例
  • 在另一个值类型的实例“字段”(类型变量)中,该值类型本身在堆栈中(出于上述原因)

它们被存储在堆中(作为对象的一部分),当:

  • 在类的实例“字段”中
  • 在自身位于堆上的值类型的实例“字段”中
  • 在静态“字段”中
  • 在数组中
  • 在作为迭代器块、异步方法的一部分的“本地”(方法变量)中,或者是 lambda 或匿名方法中的“捕获”变量(所有这些都会导致将本地提升到由编译器生成的类上的字段)
  • 当“装箱”时 - 即转换为引用类型(objectdynamicEnumValueType(是的:ValueType 是引用类型;很有趣,嗯?),@ 987654328@等)

【讨论】:

  • 为了清楚起见,我会添加参数的大小写......但也许它是一个蠕虫罐......一个非引用非输出值类型参数?
  • @xanatos 添加为“浮动值”下的子项
  • 对于您说它们在堆栈上的所有示例,它们实际上可能位于 CPU 寄存器中,不是吗?
  • @Damien_The_Unbeliever 我在这里将我的答案限制在 IL / CLI 级别。 JIT 做什么完全取决于 JIT。哎呀,如果你愿意,我怀疑你可以编写一个无堆栈 JIT(如无堆栈 python)
  • 让我对堆和堆栈存储的讨论有意义的唯一方法是,如果我们谈论的是运行时实际发生的事情,并且必须在 JITting 发生之后。在 IL 级别,唯一“在范围内”的堆栈是评估堆栈,它不是存储局部变量的地方。
【解决方案2】:

我的问题是:值类型何时存储在堆栈中?

来自The Truth About Value Types

[I]在桌面 CLR 上的 C# 的 Microsoft 实现中,当值是局部变量或临时值而不是 lambda 或匿名方法的封闭局部变量时,值类型存储在堆栈中,并且方法体不是迭代器块,jitter选择不注册值

【讨论】:

  • 当然,该引用早于async - 在这方面它们几乎与迭代器块相同。
  • 好的。但是这个变量是在类中初始化的吗?
【解决方案3】:

第一次搜索您的问题时,您会看到 Eric Lippert 的 The Truth About Value Types,它从最重要的部分开始:它几乎总是无关紧要的。那么,你为什么想知道?你会以不同的方式编程吗?

无论如何:

事实是:分配机制的选择只与存储所需的已知生命周期有关。

【讨论】:

    【解决方案4】:

    确切地说,堆栈和堆是(或应该是)irrelevant in managed environments

    实际上,局部变量值类型(C# 中的structs倾向于在堆栈上分配。不过也有分配on the heap instead的情况。

    其中一种情况是当它们被装箱时。装箱意味着将Int32 用作Object,例如通过将其传递给采用object 参数的方法。造成这种情况的一个原因是多态性:结构不携带 vTable 指针,因此无法进行动态虚拟方法解析(例如 ToString() 等方法) - 但它们是密封的,因此它们可以静态解析。另一方面,如果一个结构被强制存储在object 引用中,则需要将其转换为一个堆分配的支持 vTable 的对象。

    当值类型是堆分配对象的一部分时,也可​​以在堆中分配值类型 - 例如,当它是类的数据成员(字段)时。

    【讨论】:

      【解决方案5】:

      另一个混淆来源似乎是您假设引用类型和值类型是两种类型的类,这是不正确的

      关键字class -> 引用类型
      关键字struct-> 值类型

      【讨论】:

      • 在 IL 级别,值类型仍然是类
      • @MarcGravell 我猜他说的是关键词,我会这样修改。
      • 我知道所有对象都是 System.Object 的子对象。但是,我的意思是如果类将值类型存储在堆栈中,我可以在哪里初始化值类型。
      猜你喜欢
      • 2011-03-01
      • 2021-01-13
      • 1970-01-01
      • 2020-11-17
      • 2011-04-02
      • 2015-03-13
      • 2013-12-06
      • 2011-12-28
      • 1970-01-01
      相关资源
      最近更新 更多