c# 静态类型 所有静态成员都存储在哪里?




c#静态类型 (3)

这个问题在这里已有答案:

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

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

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

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

  • 静态只是一生。
  • 静态引用类型(myStr)将在堆上运行一生。
  • 静态值类型(myInt)将在堆栈中持续一生。

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

混乱1号:

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

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

困惑2:

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

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

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


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

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

here阅读更多。


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

  • 当你要求静态场时,就在那里
  • 在使用该类型之前,会在某个时刻执行静态构造函数

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

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

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

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

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


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

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

这不一定是这种情况,您可以阅读this博客以获取更多信息。

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

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

它没有在规范中指定。





heap