.Net Discovery 系列之七–深入理解.Net垃圾收集機制(拾貝篇) 發布在新年第一秒

來源:互聯網
上載者:User

    新年伊始,部落格園新年第一秒的第一篇文章,Net Discovery 系列之七--深入理解.Net垃圾收集機制(拾貝篇),送給各位園友新年禮物,各位互勉,新年同樂,平安幸福!

    關於.Net垃圾收集器(Garbage Collection),Aicken已經在“.Net Discovery 系列”文章中有2篇的涉及,這一篇文章是對上2篇文章的補充,關於“.Net Discovery 系列”文章索引請見本文結尾。

    第一節.記憶體回收演算法與完整收集(Full GC)

    垃圾收集器就是跟蹤所有被引用到的對象,整理對象不再被引用的對象,回收相應的記憶體,它使用“標記與清除”演算法,分兩步回收對象:

    Step 1.Mark-Sweep :從應用程式的root出發,利用相互參考關聯性,遍曆其在Heap上動態分配的所有對象,指明需要回收的對象,標記出那些存活的對象,予以標記。

    Step 2.Compact: 對記憶體中存活的對象進行移動,修改它們的指標,使之在記憶體中連續,這樣閒置記憶體也就連續了,即完成了記憶體釋放工作,也解決了記憶體片段問題,這個過程也可以成為指標的壓縮。

    垃圾收集器一般將託管堆中的對象分為3代,這可以通過調用GC.MaxGeneration得知,對象按照存在時間長短進行分代,最短的分在第0代,最長的分在第2代,第2代中的對象往往是比較大的,第二代空間被稱作Large Object Heap,對於2代對象的回收,與第0、1代回收方式相比最大的不同在於,沒有了指標移動的壓縮過程。

      

                                  圖1 對象的回收

 

    如所示,左邊的地區為第一次GC時的結構,需要注意的是GC標記的是那些存活的對象,而不是需要回收的,所以第一次回收,對象B、D沒有被標記,所以被回收了,之後GC移動了對象記憶體指標,使空間連續。

    接下來看中間的部分,第二次GC開始了,C對象沒有被標記,所以被回收了,接下來A、D、F三個對象被壓縮,形成連續的記憶體空間,並且形成了第1、2、3代地區。

    接下來看最右邊的部分,D對象沒有被標記,由於D對象處於第2代中,所以回收D對象後,GC沒有啟動壓縮步驟,因為對於大對象的指標移動,資源耗費成本很高。

    對於第2代的GC稱為Full GC,新分配的對象在第0代(0代空間最大長度通常為256K),按地址順序分配,它們通常是一些局部變數;第1代(1代空間最大長度通常為2 MB)是經過0代垃圾收集後仍然駐留在記憶體中的對象,它們通常是一些如表單,按鈕等對象;第2代是經曆過幾次垃圾收集後仍然駐留在記憶體中的對象,它們通常是一些應用程式物件。

    可見一次Full GC需要的資源是最多的,可能是幾秒或十幾秒。

    託管堆的記憶體配置以段(Segment)為單位,CLR啟動時通常為GC Heap建立2個段,分別用來儲存第0、1代對象和第2代對象,以下是通過Windbg工具查看到的GC Heap情況:

 

圖2 WinDbg 查看GC Heap情況

    可以看出,GC堆被分成了兩個段,三代,每代起始地址十進位差值為12。

    在理解方面需要注意的是,GC回收的是程式中的參考型別,實值型別是儲存在堆棧之中,當實值型別對象出了範圍後會自動釋放記憶體----即彈棧,不需要垃圾收集器管理。

    第二節.GC的工作模式

    GC的工作模式分3種,Workstation GC with Concurrent GC off、 Workstation GC with Concurrent GC on、Server GC ,在.Net 2.0以上版本可以通過修改Config檔案來改變GC工作模式,例如啟用Server GC:

 

<configuration> 
<runtime>
<gcServer enabled="true" />
</runtime>
</configuration>

 

    或者通過.Net組態工具,查看“我的電腦”節點屬性可以方便的改變GC工作模式,如:

 

圖3 GC工作模式

 

    Workstation GC without Concurrent: 用於單CPU的伺服器,策略引擎會調節GC工作頻率,使用掛起->尋找與標記->壓縮->恢複的流程進行GC工作。

    Workstation GC with Concurrent: Concurrent GC與Non Concurrent GC模式相比,有著更敏捷的反應速度,Winform應用程式和Windows services 服務程式預設採用這種模式,單CPU機器上只能使用workstation GC方式,預設為 Workstation GC with Concurrent。

    在這種模式下,第0、1代的收集仍然是要暫時掛起應用程式的,只有在收集第2代時,才會平行處理,這種並行收集是利用多CPU

對Full GC進行平行處理,具體原理是將Full GC過程切分成多個短暫子過程對線程進行凍結,線上程凍結時間之外,應用程式仍然可

以正常運行。這主要通過將0代空間設定的很大,使Full GC時,CLR仍然能夠在0代中進行記憶體配置,如果Full GC時0代記憶體也已用盡,那麼應用程式將被掛起,等待Full GC的完成。

    Server GC: 用於多CPU的伺服器,這種GC模式有著很高的效能和效率。這種模式下,CLR為每個CPU建立一個專用的GC線程,每個CPU可以獨立的為相應的heap執行GC操作,這些GC線程是以非並發的形式工作的,收集工作與線程正常工作不能同時進行,這就是說第0、1、2代的收集都會掛起應用線程。

    在.Net 4.0中,有一種新的垃圾收集機制,叫做後台收集。這種機制以concurrent GC為基礎的,如上文所講,Workstation GC with Concurrent模式中,在Full GC過程時,CLR仍然能夠在0代中進行記憶體配置,如果Full GC時0代記憶體也已用盡,那麼應用程式將被掛起,等待Full GC的完成。

    這個過程在後台收集機制中是這樣工作的,在進行Full GC時可以同時進行第0、1代收集,並且後台收集是一個獨立線程完成的,這個進程任務優先順序低於第0、1代收集,如果在後台收集中需要對第0、1代收集,後台收集將會等待第0、1代收集完成後再進行工

作,當然第0、1代收集是需要短暫掛起應用的。

    後台收集還會根據策略引擎的指示,動態調節第0、1代的容量,減少前台收集(第0、1代收集)次數。

    第三節 .Net 4.0中的垃圾收集器

    在.Net 3.5 SP1中,FrameWork中新增了如下方法,並且在4.0中進行了最佳化,GC.RegisterForFullGCNotification 、GC.WaitForFullGCApproach 、GC.WaitForFullGCComplete 、GC.CancelFullGCNotification,這幾個方法都是針對Full GC(完整收集)的。

1.GC.RegisterForFullGCNotification:這個方法將返回一個將要Full GC的訊號通知,該方法有2個參數:
  int maxGenerationThreshold
int largeObjectHeapThreshold
    這兩個參數的含義是指的是第2代中存活的對象個數和大對象堆中對象個數,滿足這兩個參數後,便會引發通知,由此看來LOH也許並不是第2代,.Net GC也許也並不只是3代,
這一點在.Net Discovery 系列之三--深入理解.Net垃圾收集機制(上)中已有描述。
2.GC.CancelFullGCNotification:取消已經註冊的垃圾收集通知
這兩個方法調用樣本:
代碼
// Variable for continual checking in the 
// While loop in the WaitForFullGCProc method.
static bool checkForNotify = false;

// Variable for suspending work
// (such servicing allocated server requests)
// after a notification is received and then
// resuming allocation after inducing a garbage collection.
static bool bAllocate = false;

// Variable for ending the example.
static bool finalExit = false;

// Collection for objects that
// simulate the server request workload.
static List<byte[]> load = new List<byte[]>();


public static void Main(string[] args)
{
try
{
// Register for a notification.
GC.RegisterForFullGCNotification(10, 10);
Console.WriteLine("Registered for GC notification.");

checkForNotify = true;
bAllocate = true;

// Start a thread using WaitForFullGCProc.
Thread thWaitForFullGC = new Thread(new ThreadStart(WaitForFullGCProc));
thWaitForFullGC.Start();

// While the thread is checking for notifications in
// WaitForFullGCProc, create objects to simulate a server workload.
try
{
int lastCollCount = 0;
int newCollCount = 0;
while (true)
{
if (bAllocate)
{
load.Add(new byte[1000]);
newCollCount = GC.CollectionCount(2);
if (newCollCount != lastCollCount)
{
// Show collection count when it increases:
Console.WriteLine("Gen 2 collection count: {0}", GC.CollectionCount(2).ToString());
lastCollCount = newCollCount;
}

// For ending the example (arbitrary).
if (newCollCount == 500)
{
finalExit = true;
checkForNotify = false;
break;
}
}
}

}
catch (OutOfMemoryException)
{
Console.WriteLine("Out of memory.");
}
finalExit = true;
checkForNotify = false;
GC.CancelFullGCNotification();

}
catch (InvalidOperationException invalidOp)
{

Console.WriteLine("GC Notifications are not supported while concurrent GC is enabled.\n"
+ invalidOp.Message);
}
}

 

 3.GC.WaitForFullGCApproach:用來獲得垃圾收集器是否將要啟動完整垃圾收集的工作,該方法返回GCNotificationStatus枚舉值,當枚舉為Succeeded時,

你應當做一些工作,例如阻止手動調用GC.Collect()方法,以免浪費資源。
該方法應與GC.WaitForFullGCComplete()同時使用,以確定CLR執行了完整垃圾收集。
代碼
// 查看是否將啟動完整收集
GCNotificationStatus s = GC.WaitForFullGCApproach();
if (s == GCNotificationStatus.Succeeded)
{
//do not GC.Collect()
}
else if (s == GCNotificationStatus.Canceled)
{
// GC.Collect()
}

 

 4.GC.WaitForFullGCComplete:
用來獲得垃圾收集器是否已經完成完整垃圾收集: 
代碼
GCNotificationStatus s = GC.WaitForFullGCApproach ();
s = GC.WaitForFullGCComplete ();
if (s == GCNotificationStatus.Succeeded) //已經完成了Full GC
{
//do not GC.Collect()
}
else if(s == GCNotificationStatus.Canceled)
{
// GC.Collect()
}

 

 

我是李鳴(Aicken) 請您繼續關注我的下一篇文章。

 

    “.Net Discovery 系列”推薦:

     .Net Discovery 系列之五--Me JIT(上)

     .Net Discovery 系列之六--Me JIT(下)

     .Net Discovery 系列之三--深入理解.Net垃圾收集機制(上)

     .Net Discovery 系列之四--深入理解.Net垃圾收集機制(下)

     .Net Discovery 系列之一--string從入門到精通(上)

     .Net Discovery 系列之二--string從入門到精通(下)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.