[翻譯] 編寫高性能 .NET 代碼--第二章 GC -- 避免使用終結器,避免大對象,避免複製緩衝區

避免使用終結器

若是沒有必要,是不須要實現一個終結器(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 類來訪問這個緩衝區的部分數據。你可使用 ArraySegment的Api來訪問原始數據,你能夠將它附加到一個建立的MemoryStram裏。你所作的這一切不會產生新的數據副本。 htm

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。若是你發現要複製緩衝區,能夠嘗試將其複製或合併到一個現有的緩衝區裏,以免任何新的內存分配。對象

下一篇:第二章 GC -- 將長生命週期對象和大對象池化blog

相關文章
相關標籤/搜索