Packing and unpacking are the operations to convert the value type and the reference type.
1. Boxing occurs when the value type is converted to the reference type
2. unpacking occurs when the reference type is converted to the value type
It is not difficult to understand the above two sentences, but it takes some space to explain them.
Let's take a look at what will happen when packing. Below is a line of the simplest Packing code.
Object obj = 1;
This line of statements assigns the integer constant 1 to the object type variable obj. It is well known that constant 1 is a value type, the value type is to be placed on the stack, and the object is a reference type, it needs to be placed on the stack; to put the value type on the stack, You need to perform a packing operation.
The IL code of this line of statements is as follows. Note the following annotations:
. Locals init (
[0] object objValue
) // The above three lines of IL indicate the local variable with the object type declared as objValue.
IL_0000: nop
IL_0001: ldc. i4.s 9 // indicates putting the integer number 9 to the top of the stack.
IL_0003: box [mscorlib] System. Int32 // execute the IL box command to apply for the heap space required by the System. Int32 type in the memory heap
IL_0008: stloc.0 // The variable on the stack is displayed and stored in a local variable with an index of 0.
The above is the operation to be performed for packing. When the packing operation is performed, it is inevitable to apply for memory space on the stack and copy the value type data on the stack to the requested heap memory space, this must consume memory and cpu resources. Let's take a look at how the unpacking operation is going on:
See the following C # code:
Object objValue = 4;
Int value = (int) objValue;
The above two lines of code will perform a packing operation to pack integer constant 4 into the objValue of the reference type object variable, and then perform another unpacking operation, store the reference variable objValue stored on the stack to the value of the partial integer value type variable.
We also need to look at the IL code:
. Locals init (
[0] object objValue,
[1] int32 'value'
) // The above IL declares two partial variables, object-type objValue and int32-type value variables.
IL_0000: nop
IL_0001: ldc. i4.4 // press integer 4 into the stack
IL_0002: box [mscorlib] System. Int32 // execute the IL box command to apply for the heap space required by the System. Int32 type in the memory heap
IL_0007: stloc.0 // The variable on the stack is displayed and stored in a local variable with an index of 0.
IL_0008: ldloc.0 // press the local variable with the index 0 (that is, the objValue variable) into the stack.
IL_0009: unbox. any [mscorlib] System. Int32 // run the IL unbox command unbox. any to convert the reference type object to System. Int32.
IL_000e: stloc.1 // store the data on the stack to the local variable with index 1, that is, value.
The binning operation is opposite to the packing operation. It is used to convert the reference type value stored on the stack to the value type and give the value type variable.
The packing and unpacking operations require additional cpu and memory resources. Therefore, a generic type is introduced after c #2.0 to reduce the consumption of packing and unpacking operations.
Next, let's take a look at the case of packing and unpacking when generics are used or when generics are not used.
--------------------------------------------------------------------------------
From: yukai technical blog