值类型何时存储在堆栈(C#)中?

Posted

技术标签:

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

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

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

【问题讨论】:

你应该再读一遍这一章。我敢肯定它在某处得到了彻底的解释。 您需要知道的就是这个问题。一些非常好的答案。 ***.com/questions/4487289/… Arrays, heap and stack and value types的可能重复 附带说明,我看过很多书弄错了。我还看到很多书错误地描述了值类型和引用类型之间的区别。所以完全有可能这里的错不是你,而是这本书。我实际上是一本在这里犯了一些错误的书的技术编辑;我一再指出错误,但没有得到纠正——所以我不得不要求从书中删除我的名字(我不是为了给它盖上橡皮图章!) 【参考方案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 的子对象。但是,我的意思是如果类将值类型存储在堆栈中,我可以在哪里初始化值类型。

以上是关于值类型何时存储在堆栈(C#)中?的主要内容,如果未能解决你的问题,请参考以下文章

核心C#(第二部分)

c#中值类型和引用类型的区别

C#知识点总结

预定义数据类型

C#基础-变量与常量

由 ref 返回的值类型变量在哪里存在?堆栈还是堆?