c# 垃圾回收(GC)優(yōu)化
GC,Garbage Collect,中文意思就是垃圾回收,指的是系統(tǒng)中的內(nèi)存的分配和回收管理。其對系統(tǒng)性能的影響是不可小覷的。今天就來說一下關于GC優(yōu)化的東西,這里并不著重說概念和理論,主要說一些實用的東西。關于概念和理論這里只做簡單說明,具體的大家可以看微軟官方文檔。
一、什么是GC
GC如其名,就是垃圾收集,當然這里僅就內(nèi)存而言。Garbage Collector(垃圾收集器,在不至于混淆的情況下也成為GC)以應用程序的root為基礎,遍歷應用程序在Heap上動態(tài)分配的所有對象[2],通過識別它們是否被引用來確定哪些對象是已經(jīng)死亡的、哪些仍需要被使用。已經(jīng)不再被應用程序的root或者別的對象所引用的對象就是已經(jīng)死亡的對象,即所謂的垃圾,需要被回收。這就是GC工作的原理。為了實現(xiàn)這個原理,GC有多種算法。比較常見的算法有Reference Counting,Mark Sweep,Copy Collection等等。目前主流的虛擬系統(tǒng).NET CLR,Java VM和Rotor都是采用的Mark Sweep算法。(此段內(nèi)容來自網(wǎng)絡)
.NET的GC機制有這樣兩個問題:
首先,GC并不是能釋放所有的資源。它不能自動釋放非托管資源。
第二,GC并不是實時性的,這將會造成系統(tǒng)性能上的瓶頸和不確定性。
GC并不是實時性的,這會造成系統(tǒng)性能上的瓶頸和不確定性。所以有了IDisposable接口,IDisposable接口定義了Dispose方法,這個方法用來供程序員顯式調(diào)用以釋放非托管資源。使用using語句可以簡化資源管理。
二、托管資源和非托管資源
托管資源指的是.NET可以自動進行回收的資源,主要是指托管堆上分配的內(nèi)存資源。托管資源的回收工作是不需要人工干預的,有.NET運行庫在合適調(diào)用垃圾回收器進行回收。
非托管資源指的是.NET不知道如何回收的資源,最常見的一類非托管資源是包裝操作系統(tǒng)資源的對象,例如文件,窗口,網(wǎng)絡連接,數(shù)據(jù)庫連接,畫刷,圖標等。這類資源,垃圾回收器在清理的時候會調(diào)用Object.Finalize()方法。默認情況下,方法是空的,對于非托管對象,需要在此方法中編寫回收非托管資源的代碼,以便垃圾回收器正確回收資源。
在.NET中,Object.Finalize()方法是無法重載的,編譯器是根據(jù)類的析構函數(shù)來自動生成Object.Finalize()方法的,所以對于包含非托管資源的類,可以將釋放非托管資源的代碼放在析構函數(shù)。
三、關于GC優(yōu)化的一個例子
正常情況下,我們是不需要去管GC這些東西的,然而GC并不是實時性的,所以我們的資源使用完后,GC什么時候回收也是不確定的,所以會帶來一些諸如內(nèi)存泄漏、內(nèi)存不足的情況,比如我們處理一個約500M的大文件,用完后GC不會立刻執(zhí)行清理來釋放內(nèi)存,因為GC不知道我們是否還會使用,所以它就等待,先去處理其他的東西,過一段時間后,發(fā)現(xiàn)這些東西不再用了,才執(zhí)行清理,釋放內(nèi)存。
下面,來介紹一下GC中用到的幾個函數(shù):
GC.SuppressFinalize(this); //請求公共語言運行時不要調(diào)用指定對象的終結器。 GC.GetTotalMemory(false); //檢索當前認為要分配的字節(jié)數(shù)。 一個參數(shù),指示此方法是否可以等待較短間隔再返回,以便系統(tǒng)回收垃圾和終結對象。 GC.Collect(); //強制對所有代進行即時垃圾回收。
GC運行機制
寫代碼前,我們先來說一下GC的運行機制。大家都知道GC是一個后臺線程,他會周期性的查找對象,然后調(diào)用Finalize()方法去消耗他,我們繼承IDispose接口,調(diào)用Dispose方法,銷毀了對象,而GC并不知道。GC依然會調(diào)用Finalize()方法,而在.NET 中Object.Finalize()方法是無法重載的,所以我們可以使用析構函數(shù)來阻止重復的釋放。我們調(diào)用完Dispose方法后,還有調(diào)用GC.SuppressFinalize(this) 方法來告訴GC,不需要在調(diào)用這些對象的Finalize()方法了。
下面,我們新建一個控制臺程序,加一個Factory類,讓他繼承自IDispose接口,代碼如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace GarbageCollect { public class Factory : IDisposable { private StringBuilder sb = new StringBuilder(); List<int> list = new List<int>(); //拼接字符串,創(chuàng)造一些內(nèi)存垃圾 public void MakeSomeGarbage() { for (int i = 0; i < 50000; i++) { sb.Append(i.ToString()); } } //銷毀類時,會調(diào)用析構函數(shù) ~Factory() { Dispose(false); } public void Dispose() { Dispose(true); } protected virtual void Dispose(bool disposing) { if (!disposing) { return; } sb = null; GC.Collect(); GC.SuppressFinalize(this); } } }
只有繼承自IDispose接口,使用這個類時才能使用Using語句,在main方法中寫如下代碼:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Diagnostics; namespace GarbageCollect { class Program { static void Main(string[] args) { using(Factory f = new Factory()) { f.MakeSomeGarbage(); Console.WriteLine("Total memory is {0} KBs.", GC.GetTotalMemory(false) / 1024); } Console.WriteLine("After GC total memory is {0} KBs.", GC.GetTotalMemory(false) / 1024); Console.Read(); } } }
運行結果如下,可以看到資源運行MakeSomeGarbage()函數(shù)后的內(nèi)存占用為1796KB,釋放后成了83Kb.
代碼運行機制:
我們寫了Dispose方法,還寫了析構函數(shù),那么他們分別什么時候被調(diào)用呢?我們分別在兩個方法上面下斷點。調(diào)試運行,你會發(fā)現(xiàn)先走到了Dispose方法上面,知道程序運行完也沒走析構函數(shù),那是因為我們調(diào)用了GC.SuppressFinalize(this)方法,如果去掉這個方法后,你會發(fā)現(xiàn)先走Dispose方法,后面又走析構函數(shù)。所以,我們可以得知,如果我們調(diào)用Dispose方法,GC就會調(diào)用析構函數(shù)去銷毀對象,從而釋放資源。
四、什么時候該調(diào)用GC.Collect
這里為了讓大家看到效果,我顯示調(diào)用的GC.Collect()方法,讓GC立刻釋放內(nèi)存,但是頻繁的調(diào)用GC.Collect()方法會降低程序的性能,除非我們程序中某些操作占用了大量內(nèi)存需要馬上釋放,才可以顯示調(diào)用。下面是官方文檔中的說明:
垃圾回收 GC 類提供 GC.Collect 方法,您可以使用該方法讓應用程序在一定程度上直接控制垃圾回收器。通常情況下,您應該避免調(diào)用任何回收方法,讓垃圾回收器獨立運行。在大多數(shù)情況下,垃圾回收器在確定執(zhí)行回收的最佳時機方面更有優(yōu)勢。但是,在某些不常發(fā)生的情況下,強制回收可以提高應用程序的性能。當應用程序代碼中某個確定的點上使用的內(nèi)存量大量減少時,在這種情況下使用 GC.Collect 方法可能比較合適。例如,應用程序可能使用引用大量非托管資源的文檔。當您的應用程序關閉該文檔時,您完全知道已經(jīng)不再需要文檔曾使用的資源了。出于性能的原因,一次全部釋放這些資源很有意義。有關更多信息,請參見 GC.Collect 方法。
在垃圾回收器執(zhí)行回收之前,它會掛起當前正在執(zhí)行的所有線程。如果不必要地多次調(diào)用 GC.Collect,這可能會造成性能問題。您還應該注意不要將調(diào)用GC.Collect 的代碼放置在程序中用戶可以經(jīng)常調(diào)用的點上。這可能會削弱垃圾回收器中優(yōu)化引擎的作用,而垃圾回收器可以確定運行垃圾回收的最佳時間。
以上就是c# 垃圾回收(GC)優(yōu)化的詳細內(nèi)容,更多關于c# 垃圾回收(GC)優(yōu)化的資料請關注腳本之家其它相關文章!
相關文章
C#實現(xiàn)解析百度天氣數(shù)據(jù),Rss解析百度新聞以及根據(jù)IP獲取所在城市的方法
這篇文章主要介紹了C#實現(xiàn)解析百度天氣數(shù)據(jù),Rss解析百度新聞以及根據(jù)IP獲取所在城市的方法,非常具有實用價值,需要的朋友可以參考下2014-10-10C#中的XML與JSON數(shù)據(jù)處理的案例詳解
在現(xiàn)代軟件開發(fā)中,數(shù)據(jù)交換和存儲的需求日益增長,而 XML 和 JSON 成為了兩種最常用的數(shù)據(jù)格式,它們各有特點,在不同的場景下有著各自的優(yōu)勢,本文將從 C# 的角度出發(fā),探討如何處理這兩種數(shù)據(jù)格式,并分享一些常見的問題及解決方法,需要的朋友可以參考下2024-09-09C#實現(xiàn)動態(tài)創(chuàng)建接口并調(diào)用的實例
這篇文章介紹了C#實現(xiàn)動態(tài)創(chuàng)建接口并調(diào)用,文中通過實例代碼介紹的非常詳細。對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-11-11C# winform 模擬鍵盤輸入自動接入訪問網(wǎng)絡的實例
本篇文章主要介紹了C# winform 模擬鍵盤輸入自動接入訪問網(wǎng)絡,有興趣的可以了解一下。2016-11-11