拳击和拆箱是否具有相同的性能?

时间:2012-03-04 12:56:05

标签: .net clr heap boxing unboxing

拳击和拆箱的性能是否相同?或者说取消装箱更快,让我们说吧?

(如果是,可以简要解释主要原因。)

由于

3 个答案:

答案 0 :(得分:10)

这部分取决于“拆箱”的含义。在IL术语中,拆箱实际上比在C#中略微减少。在C#中,“拆箱”总是涉及在某处复制值,而在IL中它只表示检查框的类型并以此方式使值可用

他们有不同的性能特征:拳击需要分配一个新对象,但没有类型检查。

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

我希望期望从长远来看,分配比类型检查更昂贵,特别是因为不仅需要预先分配成本,而且以后会发现相应的垃圾回收。< / p>

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

答案 1 :(得分:0)

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

Int32 v1 = 5;

v1在堆栈上分配。

Object r = v1; // boxing

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

但是,执行此代码时:

Int32 v2 = r; //unboxing

会发生什么情况,编译器获取指向r自身框中的值的指针,然后将其复制到v2

答案 2 :(得分:0)

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

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

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

其次,在拳击案例中,必须在堆上分配引用类型,这将保留我们的值。这涉及相当多的内务管理,例如查找备用内存,将适当的对象头写入内存,以及整数本身的值。

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

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

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