关于价值类型的困惑

时间:2010-01-29 21:18:47

标签: c# .net

如果我声明一个Object类的实例,我对一点感到困惑。它将在堆上保留,但是当我声明,从System.ValueType派生的任何原始类型实例(它进一步派生自Object类)时,Object类使用它的部分也保留在堆栈上。

为什么会这样,或者Object类是否占用空间?

4 个答案:

答案 0 :(得分:6)

你的推理似乎是这样的:

  • System.Int32派生自System.Object
  • 派生类型总是以与其基本类型
  • 相同的方式在内存中布局
  • 因此,System.Int32在内存中与System.Object
  • 相同

第二个前提是假的。派生和内存布局几乎没有任何关系。你认为这个前提是真的吗?如果是这样,是什么导致你相信它?

更新:我认为描述一个值类型的方法调用是如何工作的。

假设您有一个值类型:

struct S { 
    public int x; 
    public override string ToString() { return "Hello!" + x; } 
}
...
S s = new S();
s.x = 0x00112233;
s.ToString();

我们会生成什么代码?代码执行此操作:

  • 为s.x保留堆栈中的四个字节。
  • 将字节00 11 22 33写入该存储器。
  • 调用方法S.ToString,将引用传递给我们刚刚在堆栈上分配的内存位置。

为什么我们需要在堆栈上存储除s.x的四个字节以外的任何内容?我们已经拥有了我们需要的所有内容来执行调用:对包含S实例的变量的引用,以及我们正在调用的确切方法实现的确切名称和位置。无需在任何地方存储与System.Object有关的任何内容。没有“对象类使用它的一部分”;我们不需要这样的东西,所以没有这样的东西。

答案 1 :(得分:3)

.Net值类型在堆栈上始终分配。对吗?

不,对不起但不总是

如果在函数中声明值类型为局部变量,则为yes,它将在堆栈中分配。

如果值类型是类的成员,那么它将作为对象的一部分存储在堆上。

答案 2 :(得分:2)

与往常一样,请参阅Eric Lippert的博客:the stack is an implementation detail。价值类型的本质特征是它们通过价值传递。 System.ValueType确实继承自System.Object,但您可以说以特殊方式处理值类型:它们始终按值复制。

答案 3 :(得分:0)

任何派生自ValueType的内容都由编译器以不同方式处理。它不是作为堆上的对象分配的,而是分配内联,即作为堆栈上的局部变量或作为另一个对象的成员。

值类型没有对象具有的任何额外数据。对象具有类型标识符和对虚方法表的引用,但值类型不需要其中任何一个。因此,Int32例如只需要实际数据的四个字节。