Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do boxing and unboxing has the same performance hit?

Do boxing and unboxing has the same performance hit? Or unboxing is faster, let's say?

(If yes, can you briefly explain the main reason.)

Thanks

like image 972
pencilCake Avatar asked Mar 04 '12 12:03

pencilCake


2 Answers

It partly depends what you mean by "unboxing". In IL terms, unboxing actually does slightly less than it does in C#. In C#, "unboxing" always involves copying the value somewhere, whereas in IL it only means checking the type of the box and making the value available that way.

They've got different performance characteristics though: boxing requires the allocation of a new object, but no type checking.

Unboxing at the IL level really only needs to check that the object you're trying to unbox really is a boxed value of the same type (or a compatible one). Then you need to add the value copy operation in C# version of unboxing.

I would expect the allocation to be more expensive in the long run than the type check, particularly because there's not only the cost of allocating up-front, but the corresponding garbage collection hit later.

As always, you should evaluate performance costs of operations in the context of your actual code. I don't expect the costs of boxing and unboxing to be significant in most modern .NET applications, where generics allow you to avoid them for collections etc.

like image 125
Jon Skeet Avatar answered Oct 13 '22 03:10

Jon Skeet


In very general terms, there are some fundamental factors determining boxing and unboxing performance in a garbage collected environment.

Let us assume that we are speaking about a 64-bit integer (e.g. long in C#) on an x64 machine. Let us further assume that this takes place inside of a stack-based virtual machine using tracing garbage collection.

First, there is the cost of moving any amount of memory from one location to another. The runtime must copy the actual value of a boxed integer onto the stack, so that we can do something useful with it. Likewise, in the inverse case, it must copy the value from the stack to the heap (where reference types are stored). This is a fairly involved operation which touches a lot of the hardware's subsystems. As far as we are concerned, this factor can be considered to have a fixed cost, being the same for both operations.

Second, in the boxing case, a reference type must be allocated on the heap, which will hold our value. This involves a fair amount of housekeeping, such as locating spare memory, writing an appropriate object header to memory, as well as the value of our integer itself.

Third, in the unboxing case, the runtime may have to perform a type check to determine whether the unboxing operation is in fact legal and would produce a correct result. In some cases it may be possible to statically infer the type of the object to be unboxed, but this is a compiler optimisation (or type system feature) as opposed to being directly related to the operation we are carrying out.

Fourth, the hidden long-term cost of our boxed integer is that it must, like any other reference type, participate in garbage collection. This means that references to it may have to be recorded, it must be traced to determine liveness and potentially needs copying to a different generation. While this is of course true for all reference types, it is a factor to consider if we are thinking about performance on this level.

In summary, the cost depends on a number of version-specific behaviour of the compiler, runtime as well as of course the hardware that we are running on. It is therefore not easy to give a straightforward answer.

like image 24
awdz9nld Avatar answered Oct 13 '22 03:10

awdz9nld