所有静态成员都存储在哪里?

时间:2016-07-27 11:43:45

标签: c# .net static stack heap

我试图了解C#如何管理内存。我坚持使用静态元素,我阅读了很多关于这个主题的博客和文章,但我找不到一个相当令人满意的答案。

让我们定义一个代码块来帮助找到答案。

class myClass
{
    static string myStr = "String Data";
    static int myInt = 12;
}

在你们分享你的答案之前,让我分享一下我对这个问题的了解。请随意同意或不同意并帮助我找到正确的答案。

  • 静态只是一生。
  • 静态引用类型(myStr)将一直存在于堆中。
  • 静态值类型(myInt)将一直处于堆栈状态。

让我感到困惑的是,我在互联网上发现了一些关于这个主题的答案。

混淆数字1:

  

程序启动时,会将所有相关程序集加载到AppDomain中。加载程序集时,将调用所有静态构造函数,包括静态字段。他们将住在那里,卸载它们的唯一方法就是卸载AppDomain。

在上面的行中,明确提到存储在AppDomain上的所有静态元素。那么为什么互联网上的每个人都说“静态”#39;元素存储在堆/堆栈上?

混淆数字2:

  

每个静态变量都存储在堆上,无论它是在引用类型还是值类型中声明。

如果每个静态变量都存储在堆上。那么为什么有些人说值类型静态变量存储在堆栈上?

请帮助我连接点以了解C#中静态变量的内存管理。非常感谢你宝贵的时间:)

3 个答案:

答案 0 :(得分:56)

首先,请注意所有这些都是实现细节。运行时唯一保证的是:

  • 当你要求静态字段时,
  • 在使用类型
  • 之前,会在某个时刻执行静态构造函数

几乎就是这样。其他所有内容都是一个实现细节 - 规范并不关心堆栈,堆或其他任何东西。它取决于运行时的实现,并且有效的运行时可以将所有内容放在堆栈上(如果需要的话)或堆上。并且不要忘记寄存器。

现在,让我们看看你已经设法提出的一些误解:

  • 静态只是一生 - 是的。它没有说明存储的时间和地点 - 只是在您提出要求时可以使用它。兼容的运行时可以自由使用它想要的任何内存,甚至永远不会在内存中加载字段(例如,将其保留在图像中,无论如何已经在内存中)
  • 静态将在堆上,终身 - 很有可能,是的。但它不是规范的一部分,并且兼容的运行时可以将它存储在任何想要的地方,或者根本不存在,只要适当的保证保持不变。另外,不要忘记"终生"意味着"至少在AppDomain的生命周期内&#34 ;;卸载域时可能会发布,也可能不会发布。
  • 静态值类型将在堆栈中持续一生 - 最有可能的是,没有。同样,一个实现细节,但堆栈具有完全不同于静态值的语义。接下来的一点将为您提供更多理由:
  • 加载assambly时,会调用所有静态构造函数,包括静态字段。 - 否。没有这样的要求,也没有这样的保证。如果你依赖于此,你的程序将会破裂(我之前已经看过很多次)。同样,一个实现细节,但在当前的MSCLR实现中,静态往往被分配在它们自己的堆中,并且需要在它们被定义的类型之前的某个时间。如果在静态构造函数中抛出异常,则可以很容易地看到这一点 - 它会导致TypeLoadException,最有可能是首先引用该类型的方法(不用说,这会使调试静态变得棘手)。
  • 引用类型在堆上,值类型在堆栈上。 - 否。这使机制与语义混淆。两者之间的唯一区别是它们的语义 - 其他一切都取决于实现。如果运行时可以保留堆栈上引用类型的引用语义,那么它是完全有效的。即使使用当前的MSCLR运行时,值类型也始终存储在堆上 - 只要它们被装箱,或者引用类型的成员,例如。

有些人可能会感到困惑。有些人不了解合同与实际实施之间的区别。有些人根本不知道他们在谈论什么。我希望有一个简单的方法可以知道哪个是哪个,但是没有。如果有疑问,你可以转到C#/ CLR规范,但这只会告诉你合同,而不是实际的现实。

托管内存的重点在于您不应该关心这些实现细节。当然,就像任何抽象一样,它会泄漏 - 通过所有不同的层和抽象来了解事物的真实情况,直到CPU微指令,内存缓存等。但依赖没什么 - 实施可以随时改变,而且过去曾经多次发生过。

答案 1 :(得分:6)

  

无论何时在RAM中加载进程,我们都可以说内存是   大致分为三个区域(在该过程中):Stack,Heap,   和Static(在.NET中,实际上是Heap中的一个特殊区域   仅称为高频堆。

     

静态部分包含“静态”成员变量和方法。什么   究竟是静态的?那些不需要的方法和变量   要创建的类的实例被定义为静态

了解更多here

答案 2 :(得分:2)

创建了一个类的实例,初始化了所有静态成员。

静态类的成员通常存储在堆上,值类型的成员通常存储在堆栈中。

这不是必须的,您可以阅读this博客了解更多信息。

来自C#,Eric Lippert的语言设计师之一。

博客显示,与普通知识相反,它不确定值类型是否在堆栈上,引用类型是否在堆上,但它们通常是。

它没有在规范中指定。

相关问题