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.)
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.)
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.
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 topic –
Hixson 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.
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
.
© 2022 - 2024 — McMap. All rights reserved.