若是沒有必要,是不須要實現一個終結器(Finalizer)。終結器的代碼主要是讓GC回收非託管資源用。它會在GC完成標記對象爲可回收後,放入一個終結器隊列裏,在由另一個線程執行隊列裏對象的終結器方法。這就意味着,若是你實現一個類的終結器,你必須保證在它在終結器執行後能被正常回收。這須要消耗一些CPU資源在清理對象上,會極大下降GC的總體效率。
若是你實現一個終結器,你也必須實現一個IDisposable接口用來清理資源,並在Dispose方法裏調用GC.SupperessFinalize(this)將對象從終結器隊列裏移除。若是你在下次回收以前,正確的調用了Disspose方法,就不會讓終結器執行。下面的栗子就是正確的演示了這個模式。html
class Foo : IDisposable { ~Foo() { Dispose(false); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (disposing) { this.managedResource.Dispose(); } // Cleanup unmanaged resourced UnsafeClose(this.handle); // If the base class is IDisposable object // make sure you call: //base.Dispose(disposing); } }
你能夠經過 [http://www.writinghighperf.net/go/15] 得到過的關於Dispose模式與終結器的更多信息。this
注意 有些人認爲終結器必定會被執行。正常狀況下沒錯,但這不是絕對的。若是一個程序被強制終止,那麼進程會當即消失,終結器天然也不會執行。固然主動退出時也許會有一個短暫的等待進程關閉時間,但若是你的終結器在終結器列表的後面,也是有可能不會被執行。此外因爲終結器隊列是循序執行,若是某個終結器進入了死循環,那麼後面的終結器就不會被執行到。終結器不是執行在GC線程裏,但他們會引起GC。.net
在分析了大量的程序代碼後,大對象的邊界被定義在85000 bytes上。任何大於等於這個邊界值的對象都會斷定爲「大對象」,須要分配在一個單獨的堆裏。
咱們但願儘量的避免在大對象堆上進行分配。這不只會致使更長的GC,也更容易形成內存碎片,讓內存的分配邊界隨着時間不對增長。
爲了不這些問題,你須要嚴格控制程序在大對象堆裏分配內容。你須要統籌安排你的對象在應用程序生存週期裏的分配方案。
LOH是不會自動壓縮的,但在.NET 4.5.1 以後,你仍是能夠經過特定方法去通知GC進行壓縮。然而,這個是你最後的手段,由於這將致使一次很長的暫停。在作這以前,你仍是好好想一想,應該如何避免進入這個狀況。線程
若是可能,你應該儘可能避免複製數據。例如:若是你打算將一個文件數據讀入MemoryStream(若是你須要一個大的緩衝區,最好作一個合併)。一旦分配了內存,每一個組件都將從這個數據裏的同一個副本里讀取數據,並將其視爲開發準則。code
若是你只須要使用這個緩衝區裏的一部分,可使用ArraySegment
var memoryStream = new MemoryStream(); var segment = new ArraySegment<byte>(memoryStream.GetBuffer(), 100, 1024); var blockStream = new MemoryStream(segment.Array, segment.Offset, segment.Count);
複製內存最大的問題不在CPU而是GC。若是你發現要複製緩衝區,能夠嘗試將其複製或合併到一個現有的緩衝區裏,以免任何新的內存分配。對象