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个字节的数据时,请使用类。
  • 存储引用类型时,请使用类。
  • 当您存储多于几千个实例时,请使用类。
  • 若是列表是长的生命周期的,请使用类。
  • 在全部其余状况下,使用结构。

相关连接:

相关文章
相关标签/搜索