关于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