在内存当道的日子里,不管何时都要考虑这些代码是否会影响程序性能呢?
在如今的世界里,几乎不会去考虑用了几百毫秒,但是在特别的场景了,每每这几百毫米确影响了整个项目的快慢。
经过了解这二者之间的性能差别,但愿帮助你们在合适的场景里选择正确的编码。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
MeasureTestB
和 MeasureTestC
这两个方法的惟一不一样在于一个是建立类 一个是建立结构。编码
MeasureTestC
仅在17毫秒内完成分配并运行,比 MeasureTestB
方法快8.6倍!线程
为何会出现这样的事情,这里发生了什么?code
不一样的在于结构和类如何存储在内存中。orm
下面是 PointClass
实例 内存布局:
该列表是一个局部变量,存放在堆栈中。引用堆上的一组 PointClass
实例
PointClass
是一个引用类型,存放在堆上。
该列表仅维护一个数组,指向存储在堆上 PointClass
实例。
观察到上图的黄色箭头,在堆上引用了不少实例。
数组是一组相同的对象,MeasureTestB
这个方法是将一组相同的对象存放在数组中。
当访问指定数组元素时,.NET运行时须要检索对象引用,而后“跟随”引用以获取PointClass
实例。
当数组元素超出范围时,.NET垃圾收集器就会开始回收PointClass
对象内存,在 MeasureTestA
方法中 的PointClassFinalized
类 其实增长了额外时间。
.NET Framework在单个线程上运行全部终结器,线程必须在垃圾回收器能够回收内存以前依次处理1,000,000个对象。
能够看到MeasureTestA
比MeasureTestB
慢1.7倍。
咱们来看看 PointStruct
的内存布局:
结构是值类型,全部 PointStruct
实例都存储在数组自己中。堆上只有一个对象。
初始化数组,.NET运行库能够将X和Y值直接写入数组里。无需在堆上建立新对象,也不须要引用它。
当访问指定数组元素时,.NET运行时能够直接检索结构。
当超出范围时,.NET垃圾回收器只须要处理单个对象。
咱们总要使用结构吗?要分状况看: