探讨.NET中装箱和拆箱的性能开销

在.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(); } } }

测试结果

运行测试程序后,得到了以下结果:

  • 字符串由于其不可变的特性,处理起来总是相对昂贵的。
  • 数值类型在装箱时大约慢了10倍。
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485