Do boxing and unboxing have the same performance hit?
Asked Answered
F

3

10

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

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

Fluff answered 4/3, 2012 at 12:56 Comment(5)
I don't have hard facts, but I would expect unboxing to be a bit faster. When you box a value type, a new object has to be created and the value has to be copied into the new object. When unboxing, only the value has to be copied from the boxed instance. So boxing adds the creation of an object. This, however, is really fast in .NET, so the difference is probably not very large. Try to avoid the whole boxing procedure in the first place if you need maximum speed. Remember that boxing creates objects that need to be cleaned up by the garbage collector.Dollop
I'll wait for someone with more concrete knowledge to write an actual answer, but unboxing does not involve memory allocation, so it should have quite a bit less overhead, both immediately and in the long run for the garbage collector.Derk
(cont'd): And finally (as a more general hint): always do your own measurements for your specific use case if you want hard facts. Identify real hot spots and don't try to optimize prematurely.Dollop
Why does it matter? Are you planning to box, but never unbox, values in your program?Mcintire
See the MSFT doc page .NET Performance Tips: Boxing and Unboxing: When a value type is boxed, an entirely new object must be created. This can take up to 20 times longer than a simple reference assignment. When unboxing, the casting process can take four times as long as an assignment.Iseult
F
14

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.

Fireproofing answered 4/3, 2012 at 13:0 Comment(1)
It may be worth pointing out the fact that any value type, ultimately in the form of one or more machine words, must always be copied when read. The IL instruction isinst must perform a copy of said value(s), and likewise any compiled C# code. Your statement "makes the value available [on the stack]" is of course true when describing the semantics of the operation, but it could easily be interpreted as although you would "get it for free", which is perhaps of importance given the topicHixson
H
2

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.

Hixson answered 10/3, 2017 at 5:18 Comment(0)
P
0

As far as I know, unboxing is much cheaper than boxing. Consider this:

Int32 v1 = 5;

v1 is allocated on stack.

Object r = v1; // boxing

Compiler takes the value of v1 and creates an object based on it. That takes some time (because of several reasons).

However, when this code is executed:

Int32 v2 = r; //unboxing

what happens is, that compiler obtains a pointer to the value boxed in r itself and then copies it to the v2.

Primm answered 27/9, 2014 at 9:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.