在.NET框架中,基本数据类型(如int、boolean、char等)可以作为对象处理。这种处理方式虽然方便,但涉及到所谓的“装箱”操作,即将值类型包装成引用类型,这会带来一定的性能开销。与此相对,Java等其他语言则不需要将基本数据类型装箱为引用类型。本文旨在通过一个简单的测试程序,探讨.NET中装箱和拆箱操作的性能开销。
首先,创建了一个测试程序,通过在ArrayList和List集合中添加和获取字符串、整数和双精度浮点数,来比较装箱和不装箱的性能差异。测试结果显示,字符串由于其不可变的特性,处理起来总是相对昂贵的。而数值类型在装箱时大约慢了10倍。因此,尽可能使用泛型集合类型是一个好的做法,这样CLR可以提前知道它正在处理的类型,从而避免装箱的开销。
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
namespace BoxingAndGenerics
{
class Program
{
static void Main()
{
const int numberOfInterations = 8000000;
var startTime = Stopwatch.GetTimestamp();
ArrayList aListOfStrings = new ArrayList();
for (var i = 0; i < numberOfInterations; i++)
{
string theString = i.ToString();
aListOfStrings.Add(theString);
string unpackedString = (string)aListOfStrings[i];
}
var ellapsedTime = (Stopwatch.GetTimestamp() - startTime) / (double)Stopwatch.Frequency;
Console.WriteLine("Time to create string array with boxing: {0}", ellapsedTime);
startTime = Stopwatch.GetTimestamp();
List aGenericListOfStrings = new List();
for (var i = 0; i < numberOfInterations; i++)
{
string theString = i.ToString();
aGenericListOfStrings.Add(theString);
string unpackedString = (string)aGenericListOfStrings[i];
}
ellapsedTime = (Stopwatch.GetTimestamp() - startTime) / (double)Stopwatch.Frequency;
Console.WriteLine("Time to create string array using Generic array: {0}", ellapsedTime);
startTime = Stopwatch.GetTimestamp();
ArrayList aListOfInts = new ArrayList();
for (var i = 0; i < numberOfInterations; i++)
{
aListOfInts.Add(i);
int unpackedInt = (int)aListOfInts[i];
}
ellapsedTime = (Stopwatch.GetTimestamp() - startTime) / (double)Stopwatch.Frequency;
Console.WriteLine("Time to create int array with boxing: {0}", ellapsedTime);
startTime = Stopwatch.GetTimestamp();
List aGenericListOfInts = new List();
for (var i = 0; i < numberOfInterations; i++)
{
aGenericListOfInts.Add(i);
int unpackedInt = (int)aGenericListOfInts[i];
}
ellapsedTime = (Stopwatch.GetTimestamp() - startTime) / (double)Stopwatch.Frequency;
Console.WriteLine("Time to create int array using Generic array: {0}", ellapsedTime);
startTime = Stopwatch.GetTimestamp();
ArrayList aListOfDoubles = new ArrayList();
for (var i = 0; i < numberOfInterations; i++)
{
double theDouble = (double)i;
aListOfDoubles.Add(theDouble);
double unpackedDouble = (double)aListOfDoubles[i];
}
ellapsedTime = (Stopwatch.GetTimestamp() - startTime) / (double)Stopwatch.Frequency;
Console.WriteLine("Time to create double array with boxing: {0}", ellapsedTime);
startTime = Stopwatch.GetTimestamp();
List aGenericListOfDoubles = new List();
for (var i = 0; i < numberOfInterations; i++)
{
double theDouble = (double)i;
aGenericListOfDoubles.Add(theDouble);
double unpackedDouble = (double)aGenericListOfDoubles[i];
}
ellapsedTime = (Stopwatch.GetTimestamp() - startTime) / (double)Stopwatch.Frequency;
Console.WriteLine("Time to create double array using Generic array: {0}", ellapsedTime);
Console.ReadLine();
}
}
}
运行测试程序后,得到了以下结果: