【问题标题】:Do boxing and unboxing has the same performance hit?装箱和拆箱是否具有相同的性能影响?
【发布时间】:2012-03-22 05:43:50
【问题描述】:

装箱和拆箱对性能的影响相同吗?还是说拆箱更快?

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

谢谢

【问题讨论】:

  • 我没有确凿的事实,但我希望拆箱会更快一些。当您对值类型进行装箱时,必须创建一个新对象,并且必须将值复制到新对象中。拆箱时,只需从装箱实例中复制值。所以装箱增加了一个对象的创建。但是,这在 .NET 中非常快,因此差异可能不是很大。如果您需要最大速度,请尽量避免整个拳击过程。请记住,装箱会创建需要由垃圾收集器清理的对象。
  • 我会等待有更具体知识的人来写一个实际的答案,但拆箱不涉及内存分配,所以它应该有相当少的开销,两者立即和长期的垃圾收集器。
  • (续):最后(作​​为更一般的提示):如果您想要确凿的事实,请始终针对您的特定用例进行自己的测量。识别真正的热点,不要过早地尝试优化。
  • 为什么重要?您是否打算在程序中对值进行装箱但从不拆箱?

标签: .net clr boxing unboxing


【解决方案1】:

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

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

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

预计从长远来看分配比类型检查更昂贵,特别是因为不仅有预先分配的成本,而且相应的垃圾收集稍后也会发生。

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

【讨论】:

  • 值得指出的事实是,任何值类型,最终以一个或多个机器字的形式,在读取时必须始终被复制。 IL 指令isinst 必须执行所述值的副本,以及任何已编译的 C# 代码。在描述操作的语义时,您的陈述“使值可用 [在堆栈上]”当然是正确的,但它可以很容易地解释为虽然您会“免费获得它”,考虑到该主题,这可能很重要
【解决方案2】:

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

Int32 v1 = 5;

v1 在堆栈上分配。

Object r = v1; // boxing

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

然而,当这段代码被执行时:

Int32 v2 = r; //unboxing

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

【讨论】:

    【解决方案3】:

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

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

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

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

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-12-25
      • 1970-01-01
      • 1970-01-01
      • 2012-07-15
      • 2016-11-23
      • 1970-01-01
      • 2011-02-28
      相关资源
      最近更新 更多