2015-02-12 92 views
1

我知道我们不初始化静态类。我们可以按类名使用它们。但它必须位于静态内存中,以便我们可以使用它们。什么时候静态类被置于静态内存中?它是在运行时还是延迟加载?.NET中的静态类初始化

+1

你检查:https://msdn.microsoft.com/en-us/library/79b3xss3.aspx? – 2015-02-12 06:30:42

+0

静态类只是“存在”。它声明的所有字段在第一次加载程序集时会在内存中给出空间。但是,在执行静态构造函数之前,这些字段的状态和值不会被初始化。 – 2015-02-12 06:49:45

+0

我不知道你认为“静态内存”是什么,也不知道为什么静态类必须放在它里面。 – 2015-02-12 07:26:59

回答

2

我怀疑你是懒惰的。我不知道你的“静态记忆”是什么意思,但我认为这是一个关于静态成员的运作以及它们如何与记忆联系的非常可行的问题。静态成员将被放置在“常规内存”中,就像任何实例成员一样。

静态实例在加载时放置在堆上(虽然它是一种不同于实例的堆,称为High Frequency Heap),但在使用前不会初始化。取决于你拥有哪些静态成员(也就是它们的类型,以及这些类型是引用还是值类型),这可能是一个很大或很小的问题。例如,如果您有一个包含200个元素的字节数组,那么只有当您使用它时才会加载(少于它最初将保存的null)。但是如果你有200个字节的元素,每个元素都会在开始时放入内存中。

换句话说,使用前,ClassA将占用比ClassB更少的内存,但在使用过程中,它们将是类似的。当然,不完全一样,但你可以想象我想要说明的一点。

static class ClassA 
{ 
    public static byte[] bytes = new byte[] { 1, 12 }; 
} 

static class ClassB 
{ 
    public static byte ByteA = 1; 
    public static byte ByteB = 12; 
} 

这是因为在ClassAbytes初始值是null,但在ClassB,也有从进程的开始存储两个值,这两者正好是0。你可以想象这会如何与其他参考值与值类型的字段相结合。

GC运行时会发生另一个区别。如果我没有弄错(尽管我不相信这是特定行为),静态成员不会被垃圾收集,直到过程终止。除此之外,您可以(松散地)将它们视为类的一个简单的,编译器强制的单例实例。


最简单的方法来确定值的这种“懒加载”将放置一个副作用的呼叫静态构造函数。喜欢的东西,

public class Foo 
{ 
    static Foo() 
    { 
     Console.WriteLine("In static constructor!"); 
    } 

    public static void Bar() 
    { 
     Console.WriteLine("In Bar!"); 
    } 
} 

放在一个小控制台应用程序的情况下,你可以很容易地确定何时调用构造函数,并推断这件事情,就是当静态成员被放置到内存中。

void Main(string[] args) 
{ 
    Console.WriteLine("First line!"); 
    Foo.Bar(); 
    Console.WriteLine("Last line!"); 
} 

这个程序outputs

First line! 
In static constructor! 
In Bar! 
Last line! 

您还可以找到在C#5.0规范(§10.12静态构造函数)这一信息,

对于封闭类类型的静态构造函数在给定的应用程序域中最多执行一次。静态构造函数的执行由应用程序域中发生的以下第一个事件触发:

  • 创建类类型的实例。
  • 引用任何类类型的静态成员。

在外行的话来说,静态成员初始化您第一次使用静态类。如果它从未使用过,那么它们永远不会被初始化。


为了将我的观点带回家,让我们看看最后一对方法。

static class Foo 
{ 
    public static int X = 2; 
    public static byte[] Bytes = new byte[] { 24, 66 }; 
} 
class Bar 
{ 
    public int X = 2; 
    public byte[] Bytes = new byte[] { 24, 66 }; 
} 

单步穿过(在IL级别),与这些类的交互会非常不同。

考虑一个方法:

void Main(string[] args) 
{ 
    // Foo is put into memory when the process spins up: 
    //  X : 0 
    //  Bytes : null 

    Console.Write(Foo.X); // During this line, Foo is initialized 
          //  X : 2 
          //  Bytes : 24, 66 

    Console.Write(Foo.X); // Nothing happens 

    Bar b = new Bar(); // During this line, Bar is put into memory, then initialized 
         //  X : 0, then "instantaneously" becomes 2 
         //  Bytes : null, then "instantaneously" becomes 24, 66 

    Console.Write(b.X); // Nothing happens 

    // Eventually, b will be cleared from memory by the garbage collector 
    // but Foo will not be, until the program closes. This sample is much 
    // too small to display that difference. 
} 
+0

谢谢你。那回答了我的问题。 – kibs 2015-02-13 03:48:13

+0

静态内存是HFH的同义词:当进程加载到RAM中时,我们可以说内存大致分为三个区域(在该进程内):Stack,Heap和Static(在.NET中,它实际上是堆内的一个特殊区域,只被称为高频堆)http://www.codeproject.com/Articles/15269/Static-Keyword-Demystified – kibs 2015-02-13 03:50:44