这里有很多人感到困惑,
普通类将其数据存储在堆中吗?和堆栈的引用(指针)。
当堆栈超出范围时,下次垃圾收集器启动并从堆中删除内存。
现在在静态类的情况下,垃圾收集器无法清理内存,因为它需要在整个程序中。并且首先无法获得参考。
所以我们打电话给Console。写,例如?程序从哪里获取参考(它存储对静态类的引用的位置)?或者只是直接调用它,但是如何?
答案 0 :(得分:16)
我认为你将内存与内存所占用的混淆了类。当您创建普通类的实例时,该实例的内存将存在于堆上。此实例的引用可能位于堆上的对象中(如果在对象的不同实例中设置成员变量);或者一个堆栈变量(如果你在一个方法中向对象声明了一个变量或者将它传递给一个函数调用),或者它可能在全局根列表中(如果它是一个静态引用,例如一个Singleton引用)。
无法实例化静态类。在任何地方都没有“引用”类(类型信息除外)。它的方法只是在CLR加载程序集时加载到内存中的函数。您可以创建一个指向其中一个方法的委托,但也不会引用该类的实例。那只是指向函数的指针。
例如,请查看以下代码:
class ObjectWrapper
{
Object obj = new Object();
}
static void Main(string[] args)
{
ObjectWrapper wrapper = new ObjectWrapper();
...
}
Main方法创建ObjectWrapper类的实例。这个实例存在于堆中。
在ObjectWrapper实例中,有一个类Object的实例存在于堆上。对这个类的引用是在实例中,所以我猜你可以把引用想象成“生活在堆中”。
现在,将其与以下代码进行比较:
class Singleton
{
static readonly instance = new Singleton();
}
Singleton对象的实例也存在于堆上。但是,引用是静态引用。它由CLR维护在全局或“根”引用列表中。
现在看看这个静态类:
class ObjectWrapper
{
Object obj = new Object();
}
static class HelperMethods
{
static int DoSomethingUseful(ObjectWrapper wrapper1)
{
ObjectWraper wrapper2 = wrapper1;
// code here
}
}
HelperMethods是一个静态类。您无法实例化HelperMethods类。堆上没有此类的任何对象。但是,在DoSomethingUseful方法中,它有两个对堆栈上ObjectWrapper类的实例的引用。传入一个,并在方法内声明一个。
答案 1 :(得分:6)
为了给你一个简单的答案,静态类被“存储”在所谓的Loader Heap上。装载机堆是特殊的,非GC的治疗,具有极其可预测和严格的增长率。当.NET应用程序启动时,实际上会创建几个AppDomain。除了主应用程序域之外,还有系统和共享应用程序域,其中包含系统命名空间和mscorelib,特殊堆(例如加载程序堆)和CLR本身。
有关详细说明,请阅读以下MSDN杂志文章:
Drill Into .NET Framework Internals to See How the CLR Creates Runtime Objects
尽管来自几年前,它仍然适用。 (但是,我不能说.NET 4.0是否已经改变了这么多。)