9

装箱和拆箱是否具有相同的性能影响?或者说,拆箱更快?

(如果有,能否简要说明主要原因。)

谢谢

4

3 回答 3

14

这部分取决于您所说的“拆箱”是什么意思。在 IL 术语中,拆箱实际上比在 C# 中做的要少一些。在 C# 中,“拆箱”总是涉及将值复制到某处,而在 IL 中,它仅意味着检查框的类型并以这种方式使值可用

但是它们有不同的性能特征:装箱需要分配一个新对象,但不需要类型检查。

在 IL 级别拆箱实际上只需要检查您尝试拆箱的对象是否真的是相同类型(或兼容的)的装箱值。然后需要在C#版本的拆箱中添加值复制操作。

从长远来看,我希望分配比类型检查更昂贵,特别是因为不仅有预先分配的成本,而且还有相应的垃圾回收命中。

与往常一样,您应该在实际代码的上下文中评估操作的性能成本。我不认为在大多数现代 .NET 应用程序中装箱和拆箱的成本会很大,在这些应用程序中,泛型允许您避免它们用于集合等。

于 2012-03-04T13:00:40.767 回答
2

一般而言,有一些基本因素决定了垃圾收集环境中的装箱和拆箱性能。

让我们假设我们谈论的long是 x64 机器上的 64 位整数(例如在 C# 中)。让我们进一步假设这发生在使用跟踪垃圾收集的基于堆栈的虚拟机内部。

首先,将任意数量的内存从一个位置移动到另一个位置是有成本的。运行时必须将装箱整数的实际值复制到堆栈上,以便我们可以用它做一些有用的事情。同样,在相反的情况下,它必须将值从堆栈复制到堆(存储引用类型的地方)。这是一个相当复杂的操作,涉及到很多硬件的子系统。就我们而言,这个因素可以被认为具有固定成本,对于两种操作来说都是相同的。

其次,在装箱的情况下,必须在堆上分配一个引用类型,它将保存我们的值。这涉及到大量的内务处理,例如定位空闲内存、将适当的对象头写入内存以及整数本身的值。

第三,在拆箱的情况下,运行时可能必须执行类型检查以确定拆箱操作是否实际上合法并会产生正确的结果。在某些情况下,可以静态推断要拆箱的对象的类型,但这是编译器优化(或类型系统功能),而不是与我们正在执行的操作直接相关。

第四,我们的装箱整数隐藏的长期成本是它必须像任何其他引用类型一样参与垃圾收集。这意味着可能必须记录对它的引用,必须对其进行跟踪以确定活跃度,并且可能需要复制到不同的代。虽然这当然适用于所有引用类型,但如果我们正在考虑此级别的性能,这是一个需要考虑的因素。

总之,成本取决于编译器的许多特定于版本的行为、运行时以及我们运行的硬件。因此,要给出一个直截了当的答案并不容易。

于 2017-03-10T05:18:43.113 回答
0

据我所知,拆箱比装箱便宜得多。考虑一下:

Int32 v1 = 5;

v1在堆栈上分配。

Object r = v1; // boxing

编译器获取 的值v1并基于它创建一个对象。这需要一些时间(由于几个原因)。

但是,当执行此代码时:

Int32 v2 = r; //unboxing

发生的情况是,该编译器获得一个指向r自身装箱的值的指针,然后将其复制到v2.

于 2014-09-27T09:14:45.627 回答