2012-10-09 55 views
2

GC代 - 考慮下面的代碼收集問題

namespace GcDemo 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      var list = new List<object>(); 
      Console.WriteLine("list is in {0} generation.", GC.GetGeneration(list)); 
      GC.Collect(); 
      Console.WriteLine("list is in {0} generation.", GC.GetGeneration(list)); 
      GC.Collect(); 
      list.Add(new object()); 
      Console.WriteLine("list is in {0} generation. object is in {1} generation.", GC.GetGeneration(list), GC.GetGeneration(list[0])); 
      GC.Collect(0); 
      Console.WriteLine("list is in {0} generation. object is in {1} generation.", GC.GetGeneration(list), GC.GetGeneration(list[0])); 

     } 
    } 
} 

列表對象在第2代,而這是唯一的參考列表[0]對象,它是在根0爲什麼它知道不收集它在GC.Collect(0)?

+0

您是否期望收集'object'實例? –

+0

@BrianRasmussen是的。 –

+0

爲什麼會這樣?它仍然紮根,因此不適合收藏。如果gen0對象不能可靠地被gen1或2中的對象所紮根,那麼整個世代的想法就毫無意義。 –

回答

2

This article對其工作原理有一個簡單的介紹;閱讀「讓世代與寫作障礙一起工作」部分。 This是另一個很好的博客文章,更詳細地解釋了techinque。

執行摘要是CLR發出代碼,因此它可以檢測Gen2對象何時寫入。它將寫入記錄到數據結構(「卡表」)中,在進行Gen0收集時檢查它們;這使得它可以找到Gen2 - > Gen0參考,而不需要花費所有物體在內存中的全部費用。

+1

非常感謝Jason,您幫助我以清晰易懂的方式獲得主題。 –

1

我說得對,你的問題是,爲什麼GC不收集list[0]

如果是這樣,那麼答案是,因爲list內部有一個對您創建的對象的引用(因爲List<T>內部有一個數組T[]來容納這些項目)。

所以大家參考鏈看起來像這樣:Program.Main() - >list - >list[0],因此GC不能(也不應該)收集該對象,無論哪一代的對象。

編輯:你從哪裏開始第0級的收集,... list[0]是在第0 +引用(見上文)=>在GC 收集list[0],但它移動到根1

+0

但我只收集第0代,列表在第2代,GC如何知道不收集list [0]? –

+0

@YairNevet:查看編輯 – ulrichb

+0

因此,GC沒有看到列表[0]給對象的引用,仍然「不知何故」知道不要收集對象,甚至不把它提升到第1代。問題是「不知何故」? –

1

主要規則非常簡單,即在沒有引用留下時收集對象。您添加到列表中的對象無法收集,列表中有一個對它的引用。該列表無法收集,您的代碼有一個參考。一直到最後的陳述。每次強制收集時,都會迫使物體進入下一代。

唯一可能混淆的是垃圾收集器可以看到該列表存儲對該對象的引用。這當然是。必然如此,你不希望物體隨機消失。 CLR所做的很大一部分是爲垃圾收集器提供儘可能快地發現它所需的信息。

可能更混淆的是,它也可以看到你的代碼有一個對列表的引用。這是抖動的一個重要部分,它構造了一個表,說明哪部分代碼引用了局部變量。自從上一條語句引用列表以來,您無法在代碼段中看到它。