2013-02-26 46 views
6
public class MyClass { 
    private static MyClass heldInstance; 

    public MyClass() { 
    heldInstance = this; 
    } 
} 

假設MyClass的實例的根源並非是任何其他方式,將這裏的私人靜態參考防止它被垃圾回收?在靜態字段中引用自身的類是否可以垃圾收集?

+1

可能的重複[做靜態成員有沒有垃圾收集?](http://stackoverflow.com/questions/6600093/do-static-members-ever-get-garbage-collected)編輯:總之,不,我不相信會。例如,在您發佈的代碼中,沒有任何理由說明爲什麼公共構造函數不能擁有if(heldInstance == null)'除此之外,_instances_中只有持有的引用自身會自己收集_eventually_一旦它確定它不再可訪問,由GC決定。 – 2013-02-26 21:37:42

+0

是的,它們在AppDomain被卸載之前收集。這是無關緊要的,除非班上有終結者。 – 2013-02-26 21:45:42

+3

該類的靜態字段所引用的實例*同等級*的事實是無關緊要的。靜態字段是根;他們會保留你放入它們的任何東西,而不管它的類型如何。 – 2013-02-26 22:11:15

回答

8

您發佈的類將不被垃圾收集。你可以給它一個控制檯輸出終結測試:

public class MyClass 
{ 
    private static MyClass heldInstance; 
    public MyClass() 
    { 
     heldInstance = this; 
    } 
    ~MyClass() 
    { 
     Console.WriteLine("Finalizer called"); 
    } 
} 
class Program 
{ 
    static void Main(string[] args) 
    { 
     var x = new MyClass(); // object created 

     x = null; // object may be eliglible for garbage collection now 

     // theoretically, a GC could happen here, but probably not, with this little memory used 
     System.Threading.Thread.Sleep(5000); 

     // so we force a GC. Now all eligible objects will definitely be collected 
     GC.Collect(2,GCCollectionMode.Forced); 

     //however their finalizers will execute in a separate thread, so we wait for them to finish 
     GC.WaitForPendingFinalizers(); 

     System.Threading.Thread.Sleep(5000); 
     Console.WriteLine("END"); 

    } 
} 

輸出將是:

END 
Finalizer called 

這意味着該類只在應用程序的最終拆除被採集,不在正規垃圾收集期間。

如果你創建這個類的多個實例是這樣的:

var x = new MyClass(); 
x = new MyClass(); 
x = new MyClass(); 
x = new MyClass(); 

然後所有除最近的一個將被垃圾收集。

你會得到

Finalizer called 
Finalizer called 
Finalizer called 
END 
Finalizer called 
+1

請注意,這僅僅是因爲'heldInstance'是靜態的。 「MyClass」的一個實例具有對自身的引用這一事實沒有什麼特別之處。所以,是的「引用自己的類」可以被垃圾回收。但是,示例中的類不能。 – dgvid 2013-02-26 22:01:08

2

垃圾回收器確定哪些對象是可達和將收集那些沒有。要確定一個對象是否可達,收集器將與所謂的開始。其中根是當前計算堆棧上的東西,也靜態字段。收集器將遵循從根到對象的引用,並從這樣的對象到任何其他對象,等等。以這種方式訪問​​的每個對象都是可訪問的,因此將保持活動狀態。

在你的情況下,靜態字段是垃圾收集器的根之一,因此它永遠不會收集由該字段引用(間接)的任何對象。但是,如果你的字段設置爲null則該場不再引用實例,該實例可以收集。