空数组初始化的性能差异

Performance difference in empty array initialization

最近一直在做performance/memory优化,卡在空数组初始化中,使用泛型方法初始化空数组:

泛型空数组的代码实现class:

    public static class EmptyArray<T>
    {
        public static readonly T[] Instance;

        static EmptyArray()
        {
            Instance = new T[0];
        }
    }

因此,无论何时创建任何类型的空数组,它都被这样调用:

var emptyStringArray = EmptyArray<string>.Instance;

这样的空数组声明已经在代码库的很多地方做了。我很困惑使用时它的性能会有什么不同:

var emptyStringArray = new string[0];

我问过上面的代码作者,他已经回复了我:

Basically, all empty arrays are readonly, and are equal to one another, which means that you can use the same instance (which will be created lazily on demand during run-time)… That should reduce the total number of allocations, reduce memory usage and GC pressure, and should result in some improvement

仍然,我无法理解 EmptyArray Instance 如何提高数组声明的性能。

使用以下方法的代码是否存在任何性能差异:

第一种方法:

var emptyStrArr = EmptyArray<string>.Instance;
var emptyFooArr = EmptyArray<Foo>.Instance;
var emptyBarArr = EmptyArray<Bar>.Instance;

第二种方法:

var emptyStrArr = new string[0];
var emptyFooArr = new Foo[0];
var emptyBarArr = new Bar[0];

在第一个代码中,static 构造函数只执行 once.So 你只是创建一个数组并一直使用它。在第二个代码中,您每次都创建一个数组实例。这就是区别。

你可以通过改变构造函数看得更清楚:

static EmptyArray()
{
   Instance = new T[0];
   Console.WriteLine("Array of "+ typeof(T) + " is created.");
}

var s = EmptyArray<string>.Instance;
s = EmptyArray<string>.Instance;
s = EmptyArray<string>.Instance;

var i = EmptyArray<int>.Instance;
i = EmptyArray<int>.Instance;

// output:
// Array of System.String is created.
// Array of System.Int32 is created.

这个:

var emptyStringArray = new string[0];

每次调用时创建一个空字符串数组的新实例,以及所有相关的内存分配开销,而这个:

public static class EmptyArray<T>
    {
        public static readonly T[] Instance;

        static EmptyArray()
        {
            Instance = new T[0];
        }
    }

只创建空字符串数组的单个实例,无论您调用 Instance 字段多少次。

只是为了说明这如何提高性能和内存你可以试试这个

using System;

namespace ConsoleApplication11
{
    class Program
    {
        static void Main(string[] args)
        {
            var str = EmptyArray<string>.Instance;
            var intTest = EmptyArray<int>.Instance;
            var intTest1 = EmptyArray<int>.Instance;  
            var str1 = EmptyArray<string>.Instance;
            Console.WriteLine(str.GetType());
            Console.WriteLine(intTest.GetType());
            if (ReferenceEquals(str,str1))
            {
                Console.WriteLine("References are equals");
            }
            if (ReferenceEquals(intTest,intTest1))             
            {
                Console.WriteLine("References are equals");
            }

        }
    }

    public static class EmptyArray<T>
    {
        public static readonly T[] Instance;

        static EmptyArray()
        {
            Instance =  new T[0];
        }
    }
}

您可以看到,即使是值类型也不需要其他分配,考虑到对象的分配和销毁会消耗时间和内存,您可以通过这样做来增强您的代码