It is really interesting to carefully understand the packing and unpacking. First of all, let's take a look at why it is packed and unpacked?
See the following code:
Class program {static void main (string [] ARGs) {arraylist array = new arraylist (); point P; // assign a for (INT I = 0; I <5; I ++) {P. X = I; // initialization value p. y = I; array. add (p); // boxed }}public struct point {public int32 X; Public int32 y ;}
5 cycles, initialize a point value type field each time, and put it in the arraylist. Struct is a value-type structure. What is stored in arraylist? Let's take a look at the add method of arraylist. The add method can be seen in msdn:
Public Virtual int add (object value ),
It can be seen that the Add parameter is of the object type, that is, the parameter it requires is an object reference. That is to say, the parameter here must be of the reference type. As for the reference type, you don't have to elaborate on it. It is nothing more than the reference of an object on the stack. However, to facilitate understanding, let's talk about the stack and stack again.
1. STACK: the stack zone is automatically allocated and released by the compiler, and stores function parameter values and local variable values.
2. Heap: the heap is assigned and released by the programmer. If the programmer does not release the heap, it may be recycled by the OS at the end of the program.
For example:
Class program {static void main (string [] ARGs) {int32 N; // This is a value type and is stored in the stack. The initial int32 value is 0; // at this time, space A = new A () is opened in the stack; // an object that is actually instantiated is saved in the heap. } Public class A {public (){}}
Back to the above question, the add method needs to reference the type parameter. What should I do? It requires packing. The so-called packing means converting a value type into a reference type. The conversion process is as follows:
1. allocate memory in the managed heap. The amount of memory allocated is the amount of memory required for each field of the value type and the amount of memory required for all objects in the managed heap with two additional members (type object pointers and synchronized block indexes.
2. Copy the value type field to the newly allocated pair memory.
3. The address of the returned object. At this time, this address is a reference to an object, and the value type has now been converted to a reference type.
In this way, the add method saves a reference to a boxed point object. This object after packing will always be in the heap, knowing that the programmer is processing or the system is garbage collection. At this time, the life cycle of the boxed Value Type exceeds the life cycle of the unboxed value type.
With the above packing, you naturally need to unpack the box, if you want to retrieve the first of the array:
Point P = (point) array [0];
What we need to do here is to get the reference of element 0 of arraylist and put it in point value type P. To achieve this purpose, first, obtain the addresses of each point field of the packed point object. This is the unpacking. Then, copy the values contained in these fields from the heap to the stack-based value type instance. Unpacking is actually the process of obtaining a reference, which points to the original value type contained in an object. In fact, the reference points to the unpacked part of the boxed instance. Therefore, unlike packing, unpacking does not need to copy any bytes in the memory. However, a copy operation is performed immediately after unpacking.
Therefore, packing and unpacking will adversely affect the program speed and memory consumption. Therefore, pay attention to when the program will automatically perform packing/unpacking operations, and avoid such situations when writing code.
Note the following exceptions when unpacking:
1. If the variable containing "reference to boxed Value Type instance" is null, nullreferenceexception is thrown.
2. If the referenced object is not a boxed instance of the expected value type, an invalidcastexception is thrown.
For example, the following code snippet:
Int32 x = 5; object o = x; int16 r = (int16) O; // throw an invalidcastexception
Because it can only be converted to the value type when it is not packed. Modify the above Code:
Int32 x = 5; object o = x; // int16 r = (int16) O; // throw invalidcastexception int16 r = (int16) (int32) O;
This is correct.
After unpacking, a field copy occurs, as shown in the following code:
// The field will be copied to Point P1; p1.x = 1; p1.y = 2; object o = p1; // binning, where p1 = (point) O is copied; // unpack, and copy the field from the boxed instance to the stack.
Let's look at the following code snippet:
// Change the packed value point P2; p2.x = 10; p2.y = 20; object o = P2; // bind P2 = (point) O; // binning p2.x = 40; // change the variable value in the stack o = P2; // bind the variable again. O references a new boxed instance.
The purpose here is to change the X value of P2 after packing to 40. In this way, you need to split the box and execute a copy field to the stack, change the field value in the stack, and then perform a packing operation. In this case, create a new boxed instance on the stack. As a result, we also see the impact of packing/unpacking and copying on program performance.
Next, let's look at the code segments for packing and unpacking:
// Binning demo int32 v = 5; object o = V; V = 123; console. writeline (V + "," + (int32) O );
It has been packed three times here. It is obvious that
Object o = v; v = 123;
But there is still a packing in console. writeline. Why? Because the writeline here is a string-type parameter, and string is known to be a reference type, so (int32) O will be packed again here. Here again illustrates the problem of using the + sign to connect strings in the program. There are several value types during the connection, so it is necessary to perform several packing operations.
However, the above Code can be modified:
// After modification, console. writeline (V. tostring () + "," + O );
So there is no packing.
Let's look at the following code:
Int32 v = 5; Object o = v; v = 123; Console.WriteLine(v); v = (Int32)o; Console.WriteLine(v);
Only one packing occurs here, that is, the object o = V here, while the console. writeline does not pack here because int, bool, and double are overloaded.
Code download: http://download.csdn.net/detail/yysyangyangyangshan/4825550