關于GC進行垃圾回收的時機 - quinn.hong

人文精神  >>>  技術的天空 溫和的思緒

前言


今天查看一個同事的代碼,發現代碼中多處地方使用了GC.Collect()方法,我問他為什么這么做,他說感覺程序中定義了好多變量,怕GC回收不及時,用GC.Collect()可以手動掌控GC進行垃圾回收。

先不說他對GC的垃圾回收機制還不了解,就是調用GC.Collect()后GC真的會不會回收這個問題都需要再深入了解一下。

 

GC.Collect


下面我們通過一個小例子,來看一下使用GC.Collect后的內存情況。

我們知道可以通過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();
        }
    }
}

我們發現地址并沒有變化!

修改一下代碼使用for循環生成多個object:

            //創建沒有引用的垃圾對象for (int i = 0; i < 30000; i++)new object();//這是我們要判定地址的對象int[] gcTest = new int[10];

重新編譯后,執行結果如下:

地址變了!

 

通過上面的代碼,我們知道GC.Collect并不是只要執行就會進行垃圾回收,實際上GC會首先判斷當前是不是真的需要進行回收,如果內存中只有很小的垃圾(碎片化不嚴重)時,這時候啟動回收顯然得不償失,影響性能。

 

總結


1. 永遠都不要手動進行GC.Collect操作。如果你認為有,需要檢查你地代碼

2. 即使當你手動進行垃圾回收時,GC還不會立即執行,它要先判斷是否真正需要回收


Cnblogs quinn.hong 2015-08-23 08:57:30

[新一篇] 你應該在大學學到的10個方面的知識

[舊一篇] 寫代碼可能是成為軟件工程師最容易的部分
回頂部
寫評論


評論集


暫無評論。

稱謂:

内容:

驗證:


返回列表