关于STRUCT优化的一个点

在西山居的这篇U3D cheatsheet中,提到: c12. 确保 struct 实现了 Equals() 和 GetHashCode()

这怎么理解?

首先,看下system.object.equals和 ReferenceEquals的实现:

public static bool ReferenceEquals (object objA, object objB)
{
return objA == objB;//这就说明 了==比较的是引用
}

 

public virtual bool Equals (object obj)
{
return object.InternalEquals (this, obj);
}

 

如果是引用类型,比较时只需比较两个引用的值(地址,指针)是否相等即可。

对于值类型的结构体,将发生由值到object的装箱操作,生成两个堆对象,地址分别存放在objA,objB中,objA==objB 必定不成立,因为没有任何两个结构体的内存地址会相同,那么它就进行InteranlEquals 的比较,这个比较是在DLL中写的,看不到源码,

通过对结构体进行1000000次equals测试发现,结构体中类型越多,越复杂,则equals越慢,而引用类型则不会这样。

测试及结论如下:

    class Program
    {
        #region 结构体内存分配测试
        struct ST
        {
            public float fx;
            //public string name;
            int ix;
            double[] adx;

            public ST(float afx, string aName)
            {
                fx = afx;
                //name = "10"; // "hello,world, 你好吗,!@#($)%%@$";
                ix = 10000000;
                adx = new double[ix];
                for(int i=0; i< ix; ++i)
                {
                    adx[i] = i * i;
                }
            }
        }
        class CX
        {
            public float fx;
            string name = "hello,world, 你好吗,!@#($)%%@$";
            string name2 = "11111122334dfasdfd";
            string name3 = "xhello,world, dssccccc$aa$";
            double[] adx = new double[100];

        }
        static void testStructMem()
        {
            ST ot = new ST();
            ST ot2 = new ST();

            var st = Stopwatch.StartNew();
            var t1 = st.ElapsedMilliseconds;
            for(int i=0; i<1000000; ++i)
            {
                var eq = ot.Equals(ot2);
            }
            var t2 = st.ElapsedMilliseconds;

            //616ms,随着类的复杂度而上升,字符串类型,数组类型最消耗
            //且,一个元素的数组与10000个元素的数组几乎没有区别,这说明消耗在类型而不在数据长度
            //由此,可以判定,在进行结构体类型的比较时,是遍历结构内的所有成员,对每个成员先判断其类型,再进行哈希值比较
            //为什么要先判类型?只比较字节码不行吗?显然不行,对相同的字节码作不同类型的解释得到的是不一样的结果
            Console.WriteLine(t2 - t1); //616ms

            var oc = new CX();
            var oc2 = new CX();
            var st2 = Stopwatch.StartNew();
            st2.Start();
            var t11 = st2.ElapsedMilliseconds;
            for(int i=0; i<1000000; ++i)
            {
                var eq = oc.Equals(oc2);
            }
            var t12 = st2.ElapsedMilliseconds;
            Console.WriteLine(t12 - t11);//5ms,与类的复杂度无关,这说明比较的是引用(地址)
        }
        #endregion

 

posted @ 2018-09-06 13:11  时空观察者9号  阅读(171)  评论(0编辑  收藏  举报