静态类的内存分配在哪里存储 C#

12
我读到了一篇关于内存分配的文章,其中提到:

单例对象存储在堆上,而静态类存储在栈上。

链接为:http://www.dotnetjalps.com/2013/06/Static-vs-Singleton-in-Csharp-Difference-between-Singleton-and-Static.html 但是在一些 Stackoverflow 的问题中,例如: How is memory allocated for a static variable? 则描述为

无论静态变量被声明为引用类型还是值类型,它们都存储在堆上。总共只有一个插槽,无论创建了多少实例。

因此我对静态类在栈或堆上存储感到困惑。静态类和单例类的内存分配方式是什么?为什么会这样分配内存?

2
类不会占用内存,但对象会。而且“静态类存储在堆栈中”的说法听起来很荒谬。 - Sriram Sakthivel
@sriram 是的。那么静态变量呢? - SivaRajini
@SivaRajini 静态变量被存储在堆上的某个位置。 - CodeTherapist
如果您使用类的实例,它将被存储在堆中,但是堆有一些用于静态和非静态变量的区域。 - Suren Srapyan
可能是静态变量的内存分配方式是怎样的?的重复问题。 - StayOnTarget
4个回答

18

类不占用内存,但对象却会。对于“静态类存储在堆栈中”的说法,我感到很荒谬。

类本身并不存储在内存中。当一个类被加载时,它们的元数据可能会被加载到内存中并缓存。除此之外,类不会存储在内存中。

请自问如果静态类存储在堆栈中,那么你怎么能够在所有线程中访问它?

静态变量

静态变量是 MethodTable 数据结构的一个重要组成部分。它们作为 MethodTable 的一部分分配,紧随方法表格插槽数组而来。所有原始静态类型都是内联的,而静态值对象(如结构体和引用类型)则通过在句柄表中创建的 OBJECTREFs 引用。MethodTable 中的 OBJECTREF 引用了 AppDomain 句柄表中的 OBJECTREF,后者又引用了堆上创建的对象实例。一旦创建,句柄表中的 OBJECTREF 将保持堆上的对象实例在 AppDomain 卸载前处于活动状态。

请参阅此文章了解更多信息。

请停止阅读来自该作者的博客文章或任何博客文章。它们完全荒谬。


1
我认为静态类具有内存。请阅读我的答案,如果我错了,请纠正我。 - Suren Srapyan
@SurenSrapyan 静态类不会被存储在任何地方。但静态字段是被存储的。它们被存储在堆中的某个特殊位置。要了解那个特殊位置是什么,请阅读我回答中的引用部分。 - Sriram Sakthivel

5

由Sriram Sakthivel解释得很好。基本上,堆内存分为两个主要部分:对象堆内存和加载器堆内存。据我理解,所有非静态引用类型都存储在对象堆中,而所有静态对象(可能是引用类型或值类型)都存储在加载器堆中。GC永远不会在加载器堆上工作,因此它们只初始化一次并在整个应用程序期间保留在内存中。


2

静态变量进入堆中的特殊区域,称为高频堆,所有静态变量都存储在内存中的高频堆中。 高频堆中的对象不会被GC回收,因此静态变量在应用程序的整个生命周期中可用。

我们需要显式地释放它,然后将其设置为null,以便GC可以清除其分配的内存。


-1

实例是通过new关键字创建的,驻留在堆中,如果没有任何指向它的指针,则将被垃圾回收。但是对于静态类,静态构造函数只会调用一次以初始化所有静态成员的内存,这些成员将驻留在全局内存位置,而不是堆栈中,并且静态成员在应用程序运行时保持活动状态,不会被垃圾回收。


1
使用 "new" 关键字创建的实例没有任何特殊之处。并且没有保证任何对象将在堆上创建。我当然可以编写 int x = new int(); - Enigmativity

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