前言
最近在看王涛大神的《你必须知道的.NET(第二版)》一书,嗯,首先膜拜一下….
在书中的第五章-品味类型中,对装箱与拆箱一节感触很深,概念本身相信每一个程序猿都不陌生,装箱是将值类型转换为引用类型 ,拆箱是将引用类型转换为值类型(ps:不小心又背了一下书),也知道装箱与拆箱过程中将带来性能上的问题,但是在实际的项目中往往会忽略这个问题,将可能带来极大的效率上的问题。问题有多大,反正我哭过。
简单对比测试
在工作之余写了个简单的测试例子,以HashTable、ArraryList、List<T>进行了简单的对比。
运行环境:Windows7_64(Cpu:i5; Ram:6GB)。
代码如下:
复制代码
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
namespace Test
{
/// <summary>
/// 装箱拆箱(HashTable ArraryList List<T>)对比
/// </summary>
class Program
{
static void Main(string[] args)
{
while (true)
{
Console.WriteLine("循环次数:");
string strcCycleNum = Console.ReadLine();
int cycleNum = 0;
if (!int.TryParse(strcCycleNum, out cycleNum))
{
Console.WriteLine("无效输入!");
continue;
}
HashTableCost(cycleNum);
ArraryListCost(cycleNum);
GenericCost(cycleNum);
}
}
/// <summary>
/// HashTable 开销测试
/// </summary>
/// <param name="cycleNum">循环次数</param>
static void HashTableCost(int cycleNum)
{
Stopwatch sw = new Stopwatch();
Hashtable hs_Test = new Hashtable();
sw.Start();
for (int i = 0; i < cycleNum; i++)
{
hs_Test.Add(i, i);
}
sw.Stop();
ConsoleInfo(cycleNum, "HashTableCost", sw.ElapsedMilliseconds);
}
/// <summary>
/// ArraryList 开销测试
/// </summary>
/// <param name="cycleNum">循环次数</param>
static void ArraryListCost(int cycleNum)
{
Stopwatch sw = new Stopwatch();
ArrayList al_Test = new ArrayList();
sw.Start();
for (int i = 0; i < cycleNum; i++)
{
al_Test.Add(i);
}
sw.Stop();
ConsoleInfo(cycleNum, "ArraryListCost", sw.ElapsedMilliseconds);
}
/// <summary>
/// 泛型 开销测试
/// </summary>
/// <param name="cycleNum">循环次数</param>
static void GenericCost(int cycleNum)
{
Stopwatch sw = new Stopwatch();
List<int> lTest = new List<int>();
sw.Start();
for (int i = 0; i < cycleNum; i++)
{
lTest.Add(i);
}
sw.Stop();
ConsoleInfo(cycleNum, "GenericCost", sw.ElapsedMilliseconds);
}
/// <summary>
/// 打印信息
/// </summary>
/// <param name="cycleNum">循环次数</param>
/// <param name="methodName">方法名称</param>
/// <param name="cost">开销</param>
static void ConsoleInfo(int cycleNum, string methodName, long cost)
{
Console.WriteLine(methodName + " 循环次数:" + cycleNum.ToString() + " 开销(毫秒):" + cost.ToString());
}
}
}
复制代码
测试结果:
测试结果值
对于测试结果还是很惊讶,循环添加1000次,3者都为0毫秒,在10W与100W次的结果出现了鲜明的对比分别为305ms,86ms,9ms。差距不是一般的大。
对代码进行分析:
// HashTable : public virtual void Add(object key, object value);
// 在Add的过程中进行了2次装箱
hs_Test.Add(i, i);
HashTable.add()都会产生2次装箱。
// public virtual int Add(object value);
// 产生了一次装箱
al_Test.Add(i);
ArraryList.add产生2次装箱。
// 由于lTest 指定了类型(List<int>)并没有产生装箱
lTest.Add(i);
List<int>没有产生装箱。
也可以通过IL对代码进行分析,这里就不再列出了。
总结
在对大量数据进行操作的时候一定要注意装箱与拆箱操作,可以用泛型代替的地方还是使用泛型吧。
在平时的一般项目中的细节也需要注意,毕竟细节决定成败,再NB的框架,也经不起这一片片的装箱与拆箱的轰炸。
(ps:隐式转换的时候要细心,在转换成字符串的时候习惯使用ToString(),毕竟是不产生装箱的。)
- NET中的类型和装箱/拆箱原理
谈到装箱拆箱,DebugLZQ相信给位园子里的博友一定可以娓娓道来,大概的意思就是值类型和引用类型的相互转换呗---值类型到引用类型叫装箱,反之则叫拆箱.这当然没有问题,可是你只知道这么多,那么Deb ...
- CLR via C# 中关于装箱拆箱的摘录
装箱: 为了将一个值类型转换成一个引用类型,要使用一个名为装箱(boxing)的机制.下面总结了对值类型的一个实例进行装箱操作时在内部发生的事情. 1.在托管堆中分配好内存.分配的内存量是值类型的各 ...
- [C#学习笔记]你真的理解拆箱装箱吗?
学习一项新知识的时候,最好的方法就是去实践它. 前言 <CLR via C#>这本神书真的是太有意思了!没错我的前言就是这个. 装箱 首先来看下,下面这段代码 可以看到,每次循环迭代都会初 ...
- Java中的自动装箱拆箱
Java中的自动装箱拆箱 一.自动装箱与自动拆箱 自动装箱就是将基本数据类型转换为包装类类型,自动拆箱就是将包装类类型转换为基本数据类型. 1 // 自动装箱 2 Integer total = 90 ...
- Java中的装箱拆箱
一) 装箱与拆箱 Java中有概念是一切皆对象,因为所有的类都默认继承自Object.但是,对于数据类型是个例外,如short,int,long,float,double, byte,char,bo ...
- 6个重要的.NET概念:栈,堆,值类型,引用类型,装箱,拆箱
引言 本篇文章主要介绍.NET中6个重要的概念:栈,堆,值类型,引用类型,装箱,拆箱.文章开始介绍当你声明一个变量时,编译器内部发生了什么,然后介绍两个重要的概念:栈和堆:最后介绍值类型和引用类型,并 ...
- box unboxing(装箱 拆箱) C#编程指南
box(装箱)消耗大 box在堆栈中创建一个新的对象,性能消耗大 int i = 123; // Boxing copies the value of i into object o. object ...
- .net学习之继承、里氏替换原则LSP、虚方法、多态、抽象类、Equals方法、接口、装箱拆箱、字符串
1.继承(1)创建子类对象的时候,在子类对象中会为子类对象的字段开辟空间,也会为父类的所有字段开辟空间,只不过父类私有的成员访问不到(2)子类从父类继承父类所有的非私有成员,但是父类的所有字段也会创建 ...
- C#装箱拆箱
. 装箱和拆箱是一个抽象的概念 2. 装箱是将值类型转换为引用类型 :拆箱是将引用类型转换为值类型 利用装箱和拆箱功能,可通过允许值类型的任何值与Object 类 ...
随机推荐
- C#中的特性 (Attribute) 入门 (一)
C#中的特性 (Attribute) 入门 (一) 饮水思源 http://www.cnblogs.com/Wind-Eagle/archive/2008/12/10/1351746.html htt ...
- requests https访问错误SSLError: certificate verify failed 及InsecureRequestWarning处理办法
转自: https://blog.csdn.net/mighty13/article/details/78076258?locationNum=3&fps=1 在使用requests访问某网站 ...
- NEUQ OJ 2004:追梦之人 (计数数位dp)
2004: 追梦之人 描述 题目描述: 为了纪念追梦人,粉丝们创造了一种新的数——“追梦数”.追梦数要满足以下两个条件:1.数字中不能出现“7”2.不能被7整除.比如:777和4396就不是追梦数,而 ...
- [HDU6203]ping ping ping
题目大意: 给你一棵树,其中有一些点是坏掉的.告诉你k个点对表示这两个点的路径上至少有1个点是坏掉的.问整棵树上至少有多少点是坏的. 思路: 贪心. 找出每组点对的LCA,对所有点对按照LCA的深度排 ...
- (Nginx) URL REWRITE
URL重写的基础介绍 把URI地址用作参数传递:URL REWRITE 最简单的是基于各种WEB服务器中的URL重写转向(Rewrite)模块的URL转换: 这样几乎可以不修改程序的实现将 news. ...
- GPS坐标定位与距离计算
Android获取当前位置(GPS和网络定位) 1.比较: GPS准确度高但耗电多,网络定位耗电少但准确度低 2.代码 ①添加权限: AndroidManifest.xml: <!-- 两种pr ...
- CentOS的update-grub2命令
这个和Ubuntu还是有些区别,在CentOS修改成如下: grub2-mkconfig -o /boot/grub2/grub.cfg
- 对话框上动态控件的创建、在Picture Control控件上显示图片
1 MFC对话框之上的动态控件的创建 对话框上的控件是MFC类的一个具体对象. 当在对话框之上使用静态控件时,可以根据类向导来为每个控件添加消息.响应函数以及变量. 当需要在对话框中动态的创建某个控 ...
- java多线程实现主线程等待子线程执行完问题
本文介绍两种主线程等待子线程的实现方式,以5个子线程来说明: 1.使用Thread的join()方法,join()方法会阻塞主线程继续向下执行. 2.使用Java.util.concurrent中的C ...
- 演示Microsoft Advertising SDK for Windows Phone 8.1
演示Microsoft Advertising SDK for Windows Phone 8.1,Only for Windows Phone 8.1 1.在References上点右键,添加引用, ...