今天查看一個同事的代碼,發現代碼中多處地方使用了GC.Collect()方法,我問他爲何這麼作,他說感受程序中定義了好多變量,怕GC回收不及時,用GC.Collect()能夠手動掌控GC進行垃圾回收。性能
先不說他對GC的垃圾回收機制還不瞭解,就是調用GC.Collect()後GC真的會不會回收這個問題都須要再深刻了解一下。spa
下面咱們經過一個小例子,來看一下使用GC.Collect後的內存狀況。code
咱們知道能夠經過GCHandle設置引用類型(可直接複製到本機結構中的類型)在GC垃圾回收時不移動地址,而且獲取地址值,那麼就能夠經過在兩次地址獲取中間加入Collect方法,來判斷GC是否真的進行了垃圾回收。對象
using System; using System.Runtime.InteropServices; namespace TestGCCollect { class Program { static void Main(string[] args) { //建立一個沒有引用的垃圾對象 new object(); //這是咱們要斷定地址的對象 int[] gcTest = new int[10]; //設定Pinned通知GC在進行回收的時候不移動地址 GCHandle gcHandle1 = GCHandle.Alloc(gcTest, GCHandleType.Pinned); //獲取gcTest在堆中的地址並輸出 IntPtr add1 = gcHandle1.AddrOfPinnedObject(); Console.WriteLine(add1.ToString()); //通知GC當程序返回的時候能夠回收 gcHandle1.Free(); //調用GC回收object垃圾 GC.Collect(); //再次獲取地址 GCHandle gcHandle2 = GCHandle.Alloc(gcTest, GCHandleType.Pinned); IntPtr add2 = gcHandle2.AddrOfPinnedObject(); Console.WriteLine(add2.ToString()); gcHandle2.Free(); Console.ReadKey(); } } }
咱們發現地址並無變化!blog
修改一下代碼使用for循環生成多個object:內存
//建立沒有引用的垃圾對象 for (int i = 0; i < 30000; i++) new object(); //這是咱們要斷定地址的對象 int[] gcTest = new int[10];
從新編譯後,執行結果以下:get
地址變了!string
經過上面的代碼,咱們知道GC.Collect並非只要執行就會進行垃圾回收,實際上GC會首先判斷當前是否是真的須要進行回收,若是內存中只有很小的垃圾(碎片化不嚴重)時,這時候啓動回收顯然得不償失,影響性能。it
1. 永遠都不要手動進行GC.Collect操做。若是你認爲有,須要檢查你地代碼for循環
2. 即便當你手動進行垃圾回收時,GC還不會當即執行,它要先判斷是否真正須要回收