深度优化往往会与代码的抽象发生冲突!

类和结构的对比

类的实例通常在堆中分配内存,并通过指针的间接引用来访问,对象的传递代价很小,只需要复制指针(32位4字节,64位8字节)
对象还有一些固定开销,32位8个字节,64位16个字节,包含了指向方法表的指针、用于多种用途的同步块字段。
但是实际空对象的大小,32位是12字节,64位是24字节,这是因为.NET会进行内存对齐,12/24是对象的最小尺寸。

结构没有多余的开销,它占用的内存就是所有内部字段之和,如果结构声明为方法内部的局部变量,那么就是在堆栈(Stack)中分配内存,如果结构声明为类的成员,那么就会占用类的内存(存放于堆中)。
如果把结构作为参数传给方法,那么就会复制结构进去。

假定在32位系统中,有个数据结构包含了16个字节的数据,数组长度为1000000.
对象数组占用的总空间:
8字节数组固定开销+
(4字节指针1000000)+
((8字节固定开销+16字节数据)
1000000)
=28MB
结构数组占用的总空间:
8个字节数组固定开销+
16个字节数据*1000000
=16MB

由此可见,结构数组占用的内存较少,除了对象的额外开销,因为内存压力增大,还会有更高的垃圾回收频率。

重写结构的Equals和GetHashCode方法

使用结构时一定要重写这两个方法,如果没有重写,则会使用默认的,而默认的实现非常糟糕,还最好实现IEquatable接口,这样结构才会有更高的性能。

  1. struct Vector : IEquatable<Vector> {
  2. public int X { get; set; }
  3. public int Y { get; set; }
  4. public int Z { get; set; }
  5. public int Magnitude { get; set; }
  6. public override bool Equals(object obj)
  7. {
  8. if (obj == null) {
  9. return false;
  10. }
  11. if (obj.GetType() != this.GetType()) {
  12. return false;
  13. }
  14. return this.Equals((Vector)obj);
  15. }
  16. public bool Equals(Vector other)
  17. {
  18. return this.X == other.X && this.Y == other.Y && this.Z == other.Z && this.Magnitude == other.Magnitude;
  19. }
  20. public override int GetHashCode()
  21. {
  22. return base.GetHashCode(); //这个重要性没有Equals的大
  23. }
  24. }

虚方法和密封类

虚方法不利于JIT编译器的优化
密封类有利于JIT编译器的优化