这里有很多人感到困惑,
普通类将其数据存储在堆中,对栈的引用(指针)在堆上。
当栈超出范围时,下一次垃圾收集器启动并从堆中删除内存。
现在,在静态类的情况下,由于需要整个程序中都存在,因此垃圾收集器无法清除内存。而且首先无法获取引用的方式。
那么例如我们调用Console.Write,程序从哪里获取它的引用呢(它将静态类的引用存储在哪里)?或者它直接调用它,但是如何执行呢?
这里有很多人感到困惑,
普通类将其数据存储在堆中,对栈的引用(指针)在堆上。
当栈超出范围时,下一次垃圾收集器启动并从堆中删除内存。
现在,在静态类的情况下,由于需要整个程序中都存在,因此垃圾收集器无法清除内存。而且首先无法获取引用的方式。
那么例如我们调用Console.Write,程序从哪里获取它的引用呢(它将静态类的引用存储在哪里)?或者它直接调用它,但是如何执行呢?
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();
}
单例对象的实例也存储在堆上。然而,引用是静态引用,并由CLR保存在全局或“根”引用列表中。
现在看看这个静态类:
class ObjectWrapper
{
Object obj = new Object();
}
static class HelperMethods
{
static int DoSomethingUseful(ObjectWrapper wrapper1)
{
ObjectWraper wrapper2 = wrapper1;
// code here
}
}
HelperMethods是一个静态类,你不能实例化HelperMethods类。在堆上不能有任何来自此类的对象。但是,在DoSomethingUseful方法中,它有两个对ObjectWrapper类实例的引用存在于栈上。一个被传递进来,另一个在方法内部声明。
要获得详细的解释,请阅读以下MSDN Magazine文章:
深入了解.NET Framework内部,看看CLR如何创建运行时对象
尽管这篇文章写于几年前,但仍然适用。(不过我无法确定.NET 4.0是否有太大变化。)