堆与堆栈分配的影响(.NET)

Jad*_*ias 21 .net c# heap performance stack

从关于Heap和Stack 的SO回答 1中,它提出了一个问题:为什么知道变量的分配位置很重要?

另一个答案,有人指出堆栈更快.这是唯一的含义吗?有人可以提供一个代码示例,其中简单的分配位置更改可以解决问题(例如,性能)?

请注意,此问题是特定于.NET的

1问题从SO中删除.

Jon*_*eet 18

只要您知道语义是什么,堆栈与堆的唯一结果就是确保您不会溢出堆栈,并意识到垃圾收集堆相关的成本.

例如,JIT 可能会注意到新创建的对象从未在当前方法之外使用(引用永远不能在其他地方转义)并在堆栈上分配它.目前它不会这样做,但这是合法的事情.

同样,C#编译器可以决定在堆上分配所有局部变量 - 堆栈只包含对MyMethodLocalVariables实例的引用,并且所有变量访问都将通过它实现.(事实上​​,委托或迭代器块捕获的变量已经具有这种行为.)

你的问题出现了,而Eric Lippert正在深入审查C# - 我有一节解释C#1中的内容,他认为开发人员不应该关心.

  • 埃里克是男人.你很幸运有这么好的评论家. (6认同)

Wim*_*nen 5

(编辑: 我的原始答案包含过度简化"结构在堆栈上分配"和混淆堆栈与vs-heap和值与引用的关系,因为它们在C#中耦合.)

对象是否存在于堆栈中是一个不太重要的实现细节.乔恩已经很好地解释了这一点.在使用类和结构体之间进行选择时,更重要的是要认识到引用类型与值类型的工作方式不同.以下面的简单类为例:

public class Foo
{
   public int X = 0;
}
Run Code Online (Sandbox Code Playgroud)

现在考虑以下代码:

Foo foo = new Foo();
Foo foo2 = foo;
foo2.X = 1;
Run Code Online (Sandbox Code Playgroud)

在此示例中,foo和foo2是对同一对象的引用.在foo2上设置X也会影响foo1.如果我们将Foo类更改为结构,则不再是这种情况.这是因为结构不能通过引用访问.分配foo2实际上会复制.

将东西放入堆栈的原因之一是垃圾收集器不必清理它.你通常不应该担心这些事情; 只是使用课程!现代垃圾收集器做得很好.一些现代虚拟机(如java 1.6)甚至可以确定在堆栈上分配对象是否安全,即使它们不是值类型.

  • 虽然您的示例和解释是正确的,但您已经证明了第一句话的反例.什么是"Foo.X"?一个int,它是一个值类型 - 但它总是存在于堆上."类是堆分配,结构是堆栈分配"的主张是过于简单化. (2认同)
  • 更好的措辞是说值类型在声明它们的地方分配。如果它们在函数中声明为局部变量,则它们位于堆栈上。如果它们被声明为类中的成员,则它们位于堆上,作为该类的一部分。 (2认同)