值类型数组如何存储在 .NET 对象堆中?

Posted

技术标签:

【中文标题】值类型数组如何存储在 .NET 对象堆中?【英文标题】:How is an array of value types stored in .NET object heap? 【发布时间】:2011-07-02 13:25:42 【问题描述】:

在 .NET 中,值类型对象(例如 int)存储在内存中。

引用类型对象需要为引用和对象分别分配内存,并且对象存储在 .NET 对象堆中。

而Array是在堆中创建的,那么int[]等值类型的数组如何存储在堆中呢?是不是意味着值类型的对象可以不用装箱就可以存放在堆中?

【问题讨论】:

我会说一切都存储在“内存”中(嗯......除了可能没有真正存储的常量和优化为无用或常量的变量)。您只能谈论内存的“类型”(寄存器/RAM/磁盘,仅谈论可直接访问的内存,因此跳过缓存)或其组织(堆栈,堆,???):-)您可能的意思“堆栈内存”,但正如您所发现的那样,这是错误的。 '值类型对象,例如 int 存储在内存中'听起来有点误导我。堆——当然——也只是一种内存.. ? 【参考方案1】:

是的,你是对的。我建议您阅读以下内容:

https://ericlippert.com/2010/09/30/the-truth-about-value-types/

非常非常好,它解释了几乎所有你想知道的东西。

【讨论】:

是这种情况吗,几乎所有时间,所有值类型都将存储在 HEAP 上 - 所有实例变量都将存储在 HEAP ...,这是正确的理解吗?【参考方案2】:

是的,数组是一种一种可以将值类型值存储在堆上而无需装箱的方式。另一个只是在普通课程中使用它:

public class Foo

    int value1;
    string name;
    // etc

Foo 实例关联的所有变量都存储在堆上。 value1 的值就是int,而name 的值是一个字符串引用。

这就是为什么“值类型存储在堆栈上,引用类型存储在堆上”的说法显然是错误的。

但是,由于 Eric Lippert 是 rightly fond of pointing out,堆栈/堆的区别是一个实现细节。例如,CLR 的未来版本可以将一些对象存储在堆栈上,前提是在方法终止后不再需要这些对象。

【讨论】:

【参考方案3】:

是的,这意味着没有对到达元素进行装箱,因为整个数组作为一个整体被“装箱”在一个 Array 对象中(尽管它不是这样称呼的)。

实际上并没有要求值类型在放入堆之前必须被装箱。您可以通过三种方式将值类型放在堆上:

    通过将其包装在常规对象中。

    通过拳击。

    通过将其包装在数组对象中。

可能有更多方法,但我认为我没有错过任何方法。)

【讨论】:

【参考方案4】:

这样想,对象在内存中的位置是由它的类型和声明的位置来定义的。如果对象是值类型,则其 value 存储在您声明变量的位置。如果对象是引用类型,则它的 reference 存储在您声明变量的位置,而实际的对象实例存在于堆中。

当您声明一个局部变量时,您就是在堆栈上声明该变量。因此,值类型的值将在堆栈上。引用类型的引用将在堆栈上,而对象实例仍在堆上。

如果您在类中声明实例变量(引用类型),则实际上是在堆中声明实例变量。值类型的值将在堆中(在对象实例中)。引用类型的引用也将在堆中(在对象实例中),对象实例将在堆中的其他位置。

如果您在结构(值类型)中声明实例变量,它所在的位置取决于底层结构的声明位置。

对于 int int[] 数组,数组是引用类型,您可以将 int 值视为该类型的“字段”,因此您的整数实际上位于堆中。

【讨论】:

以上是关于值类型数组如何存储在 .NET 对象堆中?的主要内容,如果未能解决你的问题,请参考以下文章

对象中的值类型也存储在堆中?

Java中数组对象的存储位置?

值类型和引用类型 区别

引用类型 与 值类型

编程语言中的值数据类型和引用数据类型之间的区别

Unity3D面试题整合