如果大多数数据都在堆上,那么堆栈内存的重要性/作用是什么?

时间:2017-07-25 12:41:44

标签: c# .net memory-management garbage-collection

我正在阅读有关Dispose模式的内容,并了解memory is allocated的方式。以下是http://codebetter.com/karlseguin/2008/04/28/foundations-of-programming-pt-7-back-to-basics-memory/的引用。

  

内存分配
  ....
  ....
  此规则的唯一例外是属于引用类型的值类型 - 例如,User类的Id属性与User类本身的实例一起出现在堆上。

这里也提到了有关Stack Overflow的问题。 memory allocation for value type inside reference type in .net

我的理解是,所有值类型无论它们在何处声明都会进入堆栈。现在这看起来不错了。在下面的代码中,i将继续存在;根据链接不在堆栈上。这是因为MyClass是引用类型,它将与堆及其所有值类型一起发送。

class MyClass()
{
    int i = 5;
}

好的,所以只有那些不是类的一部分的值类型转到堆栈内存然后。对?但是,几乎所有像C#这样的Dot Net语言都是在课堂上。究竟是什么去堆栈内存?

这个answer解释了堆积的值类型。

如果是这种情况,堆栈内存中几乎没有甚至几乎没有。

我怀疑我误解了什么。

如果几乎​​所有数据都进入堆内存,我不明白堆栈内存的重要性/作用。

请解释。

以下两篇文章以简单的方式解释了很多关于内存管理的内容。

https://blogs.msdn.microsoft.com/ericlippert/2009/04/27/the-stack-is-an-implementation-detail-part-one/

https://blogs.msdn.microsoft.com/ericlippert/2009/05/04/the-stack-is-an-implementation-detail-part-two/

1 个答案:

答案 0 :(得分:9)

不要将其视为“堆叠”和“堆积”。可以将其视为短期记忆长期记忆。现在,很容易知道堆栈上发生了什么以及堆上发生了什么。 变量的生命周期是否长于当前方法的激活?如果是,那么它不是短暂的,而且必须在堆上。如果是,则可以进入堆栈。

例如:

class C {
  void M() {
    string s = Whatever();
    Something(s);
  }
}

本地变量s可以用于短期池,因为它的持续时间不会超过方法的激活时间。

现在,你可能会说等一下,string是一个引用类型,所以它肯定会在堆上。不,它没有。 字符串在堆上,但变量不包含字符串。字符串是引用类型,因此变量包含引用引用可以在堆栈中引用的东西在堆上,但引用本身是一个值,它可以放在堆栈上。

所以不要以为任何事物的类型都决定了它的存储位置。这种类型无关紧要。值类型或引用类型的变量如果是短期的,则可以在短期池中进行,如果不是,则必须在长期池中进行。

现在呢

class C { 
  void M() {
    int i = Whatever();
    X(() => i)
  }
}

现在我可以上堆吗?不,X可以存储传入的委托的副本,该委托需要知道i的值,因此该变量需要比方法M的激活更长时间,所以i继续长期存在。 i在这里堆。

同样,它是一个int的事实完全无关紧要。它是一个变量,它存在很长时间,因此它会堆积。

类的字段或数组的元素怎么样?那些是变数。只要类实例或数组实例存在,它们就会存在,因此它们的生命周期是不可预测的,因此它们会长期存在。

为什么我们有短期游泳池和长期游泳池?因为与长期池的垃圾收集器相比,短期池的垃圾收集器非常快速且便宜。因此,我们希望能够在可能的情况下在短期池中生成变量 - 即生命周期