前言

在内存当道的日子里,无论什么时候都要考虑这些代码是否会影响程序性能呢?

在现在的世界里,几乎不会去考虑用了几百毫秒,可是在特别的场景了,往往这几百毫米确影响了整个项目的快慢。

通过了解这两者之间的性能差异,希望帮助大家在合适的场景里选择正确的编码。

实例

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 实例

方法 MeasureTestB 创建了100万个 PointClass 实例

方法 MeasureTestC 创建了100万个 PointStruct 实例

您认为哪种方法最快?

MeasureTestBMeasureTestC 这两个方法的唯一不同在于一个是创建类 一个是创建结构。

MeasureTestC 仅在17毫秒内完成分配并运行,比 MeasureTestB 方法快8.6倍!

为什么会出现这样的事情,这里发生了什么?

不同的在于结构和类如何存储在内存中。

下面是 PointClass 实例 内存布局:

该列表是一个局部变量,存放在堆栈中。引用堆上的一组 PointClass实例

PointClass 是一个引用类型,存放在堆上。

该列表仅维护一个数组,指向存储在堆上 PointClass 实例。

观察到上图的黄色箭头,在堆上引用了很多实例。

数组是一组相同的对象,MeasureTestB 这个方法是将一组相同的对象存放在数组中。

当访问指定数组元素时,.NET运行时需要检索对象引用,然后“跟随”引用以获取PointClass实例。

当数组元素超出范围时,.NET垃圾收集器就会开始回收PointClass对象内存,在 MeasureTestA 方法中 的PointClassFinalized类 其实增加了额外时间。

.NET Framework在单个线程上运行所有终结器,线程必须在垃圾回收器可以回收内存之前依次处理1,000,000个对象。

可以看到MeasureTestAMeasureTestB慢1.7倍。

我们来看看 PointStruct 的内存布局:

结构是值类型,所有 PointStruct 实例都存储在数组本身中。堆上只有一个对象。

初始化数组,.NET运行库可以将X和Y值直接写入数组里。无需在堆上创建新对象,也不需要引用它。

当访问指定数组元素时,.NET运行时可以直接检索结构。

当超出范围时,.NET垃圾回收器只需要处理单个对象。

总结

我们总要使用结构吗?要分情况看:

  • 当您存储超过30-40个字节的数据时,请使用类。
  • 存储引用类型时,请使用类。
  • 当您存储多于几千个实例时,请使用类。
  • 如果列表是长的生命周期的,请使用类。
  • 在所有其他情况下,使用结构。

相关链接:

C#中谁最快:结构还是类?的更多相关文章

  1. .net(C#)中结构和类的区别

    static void Main(string[] args) { //类型 //结构:值类型 //类:引用类型 //声明的语法:class struct //在类中,构造函数里,既可以给字段赋值,也 ...

  2. C#中结构与类的区别

    一.类与结构的示例比较: 结构示例: public struct Person { string Name; int height; int weight public bool overWeight ...

  3. .NET中结构和类的区别

    最近在学习Swift语言,看到了枚举这一章,Swift可以支持在枚举中定义方法...于是想到了回顾一下.NET中枚举.结构.类之间区别. 枚举在.NET较为简单,这里就不作比较,只谈谈结构和类. 1. ...

  4. C++中结构和类的区别

    首先从从语言角度来看,c语言是一种结构化的语言,便于按照模块化的方式来组织程序,易于程序员的调试和维护,而对于c++来说,我么可以认为它是标准c的超集.实际上所有的c程序也是c++程序.但两者之间还是 ...

  5. 如何使用CSS3中的结构伪类选择器和伪元素选择器

    结构伪类选择器介绍 结构伪类选择器是用来处理一些特殊的效果. 结构伪类选择器属性说明表 属性 描述 E:first-child 匹配E元素的第一个子元素. E:last-child 匹配E元素的最后一 ...

  6. [AI开发]视频结构化类应用的局限性

    算法不是通用的,基于深度学习的应用系统不但做不到通用,即使对于同一类业务场景,还需要为每个场景做定制.特殊处理,这样才能有可能到达实用标准.这种局限性在计算机视觉领域的应用中表现得尤其突出,本文介绍基 ...

  7. 5.Swift枚举|结构体|类|属性|方法|下标脚本|继承

    1. 枚举: ->在Swift中依然适用整数来标示枚举值,需搭配case关键字 enum  Celebrity{  case DongXie,XiDu,Nandi,BeiGai }  // 从左 ...

  8. CSS3 结构伪类选择器 详解

    1 CSS3 结构伪类选择器 1.E:root 匹配E元素所在的根元素 即:html 2. E:nth-child(n) (1)匹配E元素的父元素中第n个子元素,(2)且该位置的子元素类型必须是E类型 ...

  9. Atitit java的异常exception 结构Throwable类

    Atitit java的异常exception 结构Throwable类 1.1. Throwable类 2.StackTrace栈轨迹1 1.2. 3.cause因由1 1.3. 4.Suppres ...

随机推荐

  1. abp(net core)+easyui+efcore仓储系统——创建应用服务(五)

    abp(net core)+easyui+efcore仓储系统目录 abp(net core)+easyui+efcore仓储系统——ABP总体介绍(一) abp(net core)+easyui+e ...

  2. pomelo使用中的常见问题

    1.端口被占用, 有进程没杀干净. 用 pomelo kill --force 命令清一下进程.

  3. Linux下docker的安装

    前言: 因为之前在自己的mac上直接使用HomeBrew的包管理安装的,使用brew install docker即可,这种方法简单,但最近想尝试在Linux下安装,费了一些时间,主要是启动docke ...

  4. T4生成实体和简单的CRUD操作

    主要跟大家交流下T4,我这里针对的是mysql,我本人比较喜欢用mysql,所以语法针对mysql,所以你要准备mysql的DLL了,同理sqlserver差不多,有兴趣可以自己写写,首先网上找了一个 ...

  5. Redis 学习笔记(篇四):整数集合和压缩列表

    整数集合 Redis 中当一个集合(set)中只包含整数,并且元素不多时,底层使用整数集合实现,否则使用字典实现. 那么: 为什么会出现整数集合呢?都使用字典存储不行吗? 整数集合在 Redis 中的 ...

  6. 前端学习【第一篇】: HTML内容

    内容概要: HTML介绍 常用标签介绍 一. HTML介绍 web服务的本质 #!/usr/bin/env python3 # _*_ coding:utf- _*_ import socket sk ...

  7. 每日一问:谈谈 SharedPreferences 的 apply() 和 commit()

    SharedPreferences 应该是任何一名 Android 初学者都知道的存储类了,它轻量,适合用于保存软件配置等参数.以键值对的 XML 文件形式存储在本地,程序卸载后也会一并清除,不会残留 ...

  8. 驰骋工作流引擎ccflow-ccbpm工作流引擎sdk表单装载逻辑处理注意事项

    cbpm工作流引擎sdk表单装载逻辑处理注意事项 关键字:驰骋工作流引擎 sdk表单 装载接口调用   说明:如果您要采用ccbpm的sdk表单开发,在表单 加载前您需要调用一个接口来获得当前节点的信 ...

  9. redis RDB 和AOF

    参考文献 Redis源码学习-AOF数据持久化原理分析(0) Redis源码学习-AOF数据持久化原理分析(1) Redis · 特性分析 · AOF Rewrite 分析 深入剖析 redis AO ...

  10. Android native进程间通信实例-socket本地通信篇之——基本通信功能

    导读: 网上看了很多篇有关socket本地通信的示例,很多都是调通服务端和客户端通信功能后就没有下文了,不太实用,真正开发中遇到的问题以及程序稳定性部分没有涉及,代码健壮性不够,本系列(socket本 ...