类的字段是存储在栈还是堆中?

33

昨天我看到了一个问题,它引发了我另外一个问题。请看下面的代码:

public class Class1
{
   int A; //as I uderstand, int is value type and therefore lives in the stack
}

class Class2
{
    Run()
   {
       Class1 instance1 = new Class1();
       instance1.A = 10;  //it points to value type, but isnt this reference (on heap)?
   }
}

那创建Class1实例时,它的字段类型也会在堆上创建吗?但是我不明白它什么时候会真正地在栈上,因为你几乎总是需要创建对象实例才能使用它的字段。


类名不允许以数字开头。 - cpalmer
离题:你那里有无效的类名。 - thelost
修复“2”的问题,别忘了加分号 :) - thelost
3个回答

60
您的理解是错误的。值类型被称为“值类型”,因为它们是按值复制的。引用类型被称为“引用类型”,因为它们是按引用复制的。“值类型总是在堆栈上”这一说法完全不正确。如果是这样的话,它们就应该被称为“堆栈类型”和“堆类型”。
事实是这是一个实现细节。不同的框架实现可以选择根据自己的喜好使用堆栈和堆。这是Microsoft实现的方式:
- 引用类型变量的值是指向堆内存的引用。引用基本上是一个32位或64位整数。 - 值类型变量的值是它的值。 - 除非局部变量在迭代器块中或者是匿名方法或lambda表达式的封闭外部变量,否则局部变量的值保存在栈上。在这些情况下,局部变量的值会保存在堆上。除非当然可以进行优化,否则根本没有存储。或者它们可以被寄存器管理,那么它们既不在栈上也不在堆上,而是在处理器寄存器中。 - 引用类型的实例变量和静态变量的值保存在堆上。
这清楚了吗?
字段“A”是值类型。由于它是一个字段,因此该变量存储在堆上。
实例变量的存储是在堆上的。

这段代码永远不会被放在堆栈上。就像我之前说的那样,只有局部变量(以及编译器生成的临时变量)才会被放在堆栈上,而它们不是lambda或匿名方法的闭合本地变量,也不在迭代块中。当然,Jitter可以完全将它们保持在堆栈之外并将它们放在寄存器中,如果有空闲的寄存器。

但实际上,我必须问一下,为什么你关心什么会放在堆栈上,什么会放在堆中?我们可以便宜地将可以放在堆栈上的东西放在堆栈上;其他所有东西都放在堆中。


1
我从John Sharp那里得到了一本书,上面写着“值类型在堆栈上创建,而引用类型在堆上创建”。我也不理解。 - Thomas
10
你为什么关心变量存储在栈上或堆上呢?因为有些面试官非常喜欢这样的问题,很多人因为到处都写着整型变量总是存储在栈上,而没有被录用。实际上,只有局部变量才会存储在栈上,这个问题并不是非黑即白。 - Laserson
2
如果那是真的,它们将被称为“堆类型”和“栈类型”。 - RBT
3
值类型的字段值随着其值类型的值而移动到任何地方。 - Eric Lippert
1
这个回答太被低估了。它应该被标记为传奇状态/必读类别。太多的面试官问某种类型是在堆栈还是堆上。这是一个可以随着版本或其他实现而改变的实现细节。而且,老实说,我看不出记忆这些信息有什么实际用途,因此......我不知道。我的答案通常是:“我不知道”。这是我最好的回答,“这是一个真正糟糕的问题。请继续。”也许乔尔可以把它加入到“最佳软件写作II”中。 - P.Brian.Mackey
显示剩余6条评论

10

本地结构(值类型)变量存储在堆栈上,类的值类型字段存储在堆上。


10
除非以下情况之一:(1)局部变量是匿名方法或lambda表达式的闭合外层局部变量;(2)该局部变量位于迭代器块中;(3)JIT编译器决定使用寄存器而不是栈。 - Eric Lippert
就instance1变量的存储而言会发生什么情况呢?它是一个引用类型,但同时它又是局部于函数Run()中的。instance1会保存在堆栈还是堆中呢? - RBT
很抱歉@EricLippert,我又来评论了,但我试图及时编辑我的上一个评论却没能成功。为了澄清我上面的问题,我想问两件事情:1.引用instance1将被保存在哪里。instance1只是一个引用,保存着实际对象实例所在的内存地址;2.类Class1的实例对象,由instance1引用,将驻留在哪里。这里的对象是Class1的一个实例,但它在Run()方法中具有局部作用域。 - RBT

3

好的,int是值类型,但是'1'(这个类名真是糟糕)是引用类型。这意味着'1'的任何实例都在堆上。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接