装箱和拆箱对性能的影响相同吗?

问题描述 投票:0回答:3

装箱和拆箱对性能的影响相同吗?或者说拆箱速度更快?

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

.net enums clr boxing
3个回答
14
投票

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

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

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

我预计

从长远来看,分配比类型检查更昂贵,特别是因为不仅有预先分配的成本,而且后面还会出现相应的垃圾收集。 一如既往,您应该在“实际”代码的上下文中评估操作的性能成本。我预计装箱和拆箱的成本在大多数现代 .NET 应用程序中不会很大,泛型允许您在集合等方面避免使用它们。

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


2
投票
long

)。让我们进一步假设这发生在使用跟踪垃圾收集的基于堆栈的虚拟机内部。

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


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

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

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

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

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


0
投票

v1
 分配在堆栈上。

Object r = v1; // boxing


编译器获取

v1
 的值并基于它创建一个对象。这需要一些时间(由于多种原因)。

但是,当执行这段代码时:


Int32 v2 = r; //unboxing

发生的情况是,编译器获得一个指向

r
 本身装箱的值的指针,然后将其复制到 
v2

    

© www.soinside.com 2019 - 2024. All rights reserved.