C#中誰最快:結構仍是類?

前言

在內存當道的日子裏,不管何時都要考慮這些代碼是否會影響程序性能呢?
在如今的世界裏,幾乎不會去考慮用了幾百毫秒,但是在特別的場景了,每每這幾百毫米確影響了整個項目的快慢。
經過了解這二者之間的性能差別,但願幫助你們在合適的場景裏選擇正確的編碼。c#

實例

public class PointClass
{
    public int X { get; set; }
    public int Y { get; set; }
    public PointClass(int x, int y)
    {
        X = x;
        Y = y;
    }
}

public class PointClassFinalized : PointClass
{
    public PointClassFinalized(int x, int y) : base(x, y)
    {
    }
    ~PointClassFinalized()
    {
        // added a finalizer to slow down the GC

    }
}

public struct PointStruct
{
    public int X { get; set; }
    public int Y { get; set; }
    public PointStruct(int x, int y)
    {
        X = x;
        Y = y;
    }
}

public class StructsTest : PerformanceTest
{
    protected override bool MeasureTestA()
    {
        // access array elements
        var list = new PointClassFinalized[Iterations];
        for (int i = 0; i < Iterations; i++)
        {
            list[i] = new PointClassFinalized(i, i);
        }
        return true;
    }

    protected override bool MeasureTestB()
    {
        // access array elements
        var list = new PointClass[Iterations];
        for (int i = 0; i < Iterations; i++)
        {
            list[i] = new PointClass(i, i);
        }
        return true;
    }

    protected override bool MeasureTestC()
    {
        // access array elements
        var list = new PointStruct[Iterations];
        for (int i = 0; i < Iterations; i++)
        {
            list[i] = new PointStruct(i, i);
        }
        return true;
    }
}

有一個PointClass和一個 PointStruct
,這二者用於存放X 和Y 兩個變量,並且還有一個 PointClassFinalized數組

方法 MeasureTestA 建立了100萬個 PointClassFinalized 實例ide

方法 MeasureTestB 建立了100萬個 PointClass 實例佈局

方法 MeasureTestC 建立了100萬個 PointStruct 實例性能

您認爲哪一種方法最快?ui

MeasureTestBMeasureTestC 這兩個方法的惟一不一樣在於一個是建立類 一個是建立結構。編碼

MeasureTestC 僅在17毫秒內完成分配並運行,比 MeasureTestB 方法快8.6倍!線程

爲何會出現這樣的事情,這裏發生了什麼?code

不一樣的在於結構和類如何存儲在內存中。orm

下面是 PointClass 實例 內存佈局:

該列表是一個局部變量,存放在堆棧中。引用堆上的一組 PointClass實例

PointClass 是一個引用類型,存放在堆上。

該列表僅維護一個數組,指向存儲在堆上 PointClass 實例。

觀察到上圖的黃色箭頭,在堆上引用了不少實例。

數組是一組相同的對象,MeasureTestB 這個方法是將一組相同的對象存放在數組中。

當訪問指定數組元素時,.NET運行時須要檢索對象引用,而後「跟隨」引用以獲取PointClass實例。

當數組元素超出範圍時,.NET垃圾收集器就會開始回收PointClass對象內存,在 MeasureTestA 方法中 的PointClassFinalized類 其實增長了額外時間。

.NET Framework在單個線程上運行全部終結器,線程必須在垃圾回收器能夠回收內存以前依次處理1,000,000個對象。

能夠看到MeasureTestAMeasureTestB慢1.7倍。

咱們來看看 PointStruct 的內存佈局:

結構是值類型,全部 PointStruct 實例都存儲在數組自己中。堆上只有一個對象。

初始化數組,.NET運行庫能夠將X和Y值直接寫入數組裏。無需在堆上建立新對象,也不須要引用它。

當訪問指定數組元素時,.NET運行時能夠直接檢索結構。

當超出範圍時,.NET垃圾回收器只須要處理單個對象。

總結

咱們總要使用結構嗎?要分狀況看:

  • 當您存儲超過30-40個字節的數據時,請使用類。
  • 存儲引用類型時,請使用類。
  • 當您存儲多於幾千個實例時,請使用類。
  • 若是列表是長的生命週期的,請使用類。
  • 在全部其餘狀況下,使用結構。

相關連接:

相關文章
相關標籤/搜索