c packing and unpacking knowledge

  • 2020-06-15 10:09:13
  • OfStack

1. Packing and unpacking is an abstract concept
2. Boxing is to convert value type to reference type;

Unboxing is converting a reference type to a value type

Using boxing and unboxing, you can link a value type to a reference type by converting any value of the allowed value type to the value of the Object type

Such as:


int val = 100; 
object obj = val; 
Console.WriteLine ( The value of the object  = {0}", obj); 

This is a boxing process that converts a value type to a reference type

int val = 100; 
object obj = val; 
int num = (int) obj; 
Console.WriteLine ("num: {0}", num); 

This is the unboxing process of converting a value type to a reference type and from a reference type to a value type

Note: Only objects that have been packed can be unpacked
3. In NET, the data type is divided into value type and reference type (not equal to the pointer type of C++). Accordingly, the memory allocation is divided into two ways: 1 is the stack and 2 is the heap (note: it is the managed heap).
Value types are allocated only on the stack.
Reference types allocate memory with managed heap.
The managed heap corresponds to garbage collection.

4: What is packing/unpacking?
Boxing: Used to store value types in the garbage collection heap. Boxing is an implicit conversion of a value type to an object type or to any interface type implemented by the value type.
Unboxing: Explicit conversion from the object type to the value type or from the interface type to the value type that implements the interface.

5: Why packing? Why convert a value type to a reference type?
One of the most common scenarios is to call a method with a parameter of type Object, which can support any type for generality. You need to box when you need to pass in a value type such as Int32.
Another use is a non-generic container, again to ensure generality, with the element type defined as Object. Therefore, to add value type data to the container, you need to box.

6: Internal operation of packing/unpacking

packing
Assign 1 object instance to the value type in the heap and copy the value to the new object. Take 3 steps.

New allocation of managed heap memory (size for value type instance size plus 1 method table pointer and 1 SyncBlockIndex).
Copies the instance field of the value type into the newly allocated memory.
Returns the address of a newly allocated object in the managed heap. This address is a reference to an object.
Some people understand this way: if Int32 is boxed, the return address points to 1 Int32. I don't think it's impossible to understand it that way either, but it does have a problem, 1 because it's not comprehensive, and 2 because it points to Int32 without saying what it really is (in the managed heap).

Split open a case
Check the object instance to make sure it is a boxed value of the given value type. Copy the value from the instance to the value type variable.
In some books, unboxing is simply a pointer to the part of the reference object that points to the value type, and content copying is the trigger of the assignment statement. I don't think it matters. The most important thing is to check the nature of the object instance. The unboxing and boxing types must match. At this point, at the IL layer, I don't see how it works.

7: Impact of packing/unpacking on performance efficiency

Obviously, in principle, when you box, you generate a brand new reference object, which can be time consuming, i.e., inefficient.
So how do you do that?
First, packing should be avoided as much as possible.
For example, in example 2 above, both cases can be avoided, in the first case, can be avoided by overloading the function. The second case can be avoided by generics.
Of course, nothing is absolute. If the code you want to change is a third party assembly, and you can't change it, you just have to box it.
For the optimization of the boxing/unboxing code, since both boxing and unboxing are implicit in C#, the fundamental approach is to analyze the code, and the most direct way to analyze is to understand the rationale for viewing the decompiled IL code.

For example, there may be extra packing in the loop body, and you can optimize it simply by pre-packing.

8. Better understanding of packing/unpacking

Packing/unpacking is not as straightforward as it sounds

For example, when boxing a reference object, there will be one more method table pointer. What's the use?

We can take this one step further by example.

Here's an example:


Struct A : ICloneable
{
public Int32 x;
public override String ToString() {
return String.Format( " {0} " ,x);
}
public object Clone() {
return MemberwiseClone();
}
}
static void main() 
{ 
A a; 
a.x = 100; 
Console.WriteLine(a.ToString()); 
Console.WriteLine(a.GetType()); 
A a2 = (A)a.Clone(); 
ICloneable c = a2; 
Ojbect o = c.Clone(); 
} 

a. ToString (). The compiler finds that A overrides the ToString method and calls the ToString directive directly. Because A is a value type, the compiler does not exhibit polymorphic behavior. Therefore, call directly, not boxed. (Note: ToString is the method of System. ValueType, the base class of A)
a. GetType(), GetType is a method inherited from System. ValueType. To call it, you need a method table pointer. (In addition, all value types are inherited from ES106en.ValueType).
a. Clone(), because A implements the Clone method, no boxing is required.
ICloneable transformation: When a2 is converted to an interface type, you must box because the interface is a reference type.
c. Clone (). Without boxing, the object that was boxed in step 1 is called in the managed heap.
Note: The above principle is based on a fundamental principle. Because unboxed value types have no method table Pointers, they cannot be used to call inherited virtual methods via value types. In addition, the interface type is 1 reference type. In my understanding, this method table pointer is similar to the virtual function table pointer of C++, which is an important basis for implementing the polymorphism mechanism of reference objects.

9: How do I change a boxed object

For a boxed object, because the specified method cannot be called directly, the method must be unboxed before being called, but unboxed again will generate a new stack instance and the boxed object cannot be modified. A little dizzy, I feel like saying tongue twisters. Here's another example :(appends the change method to the previous example)


public void Change(Int32 x) { 
this.x = x; 
} 

Call:


A a = new A(); 
a.x = 100; 
Object o = a; // Packing into o, The following , Want to change o The value of the 
((A)o).Change(200); // Get rid of? ? Don't break 

The reason for this change is that when o unboxing, it generates a temporary stack instance of A, so the change is based on temporary A, not the boxing object.

(Note: In managed C++, you are allowed to directly fetch the instance reference obtained in step 1 when unboxing, but not C#.)
So what do you do?
Well, with the interface, the same effect can be achieved.
The implementation is as follows:


interface IChange { 
void Change(Int32 x); 
} 
struct A : IChange { 
 ...  
} 

Call:


((IChange)o).Change(200);// Have you changed it? Get rid of the 

Why can we change it now?

When converting o to IChange, there is no re-boxing and certainly no unboxing because o is already a reference type and because it is of IChange type, you can call Change directly and change the fields in the boxed object to the desired effect.

10. To convert value type to reference type, boxing operation is required (boxing) :

First allocate memory from the managed heap for the newly generated reference object
The data of the value type is then copied into the memory just allocated
Returns the address of a newly allocated object in the managed heap
As you can see, one boxing involves allocating memory and copying data, two operations that affect performance.

To convert a reference type to a value type, unboxing is required (unboxing) :

The first step is to get the address of the field in the managed heap that belongs to the value type, which is technically unboxing.
Copies the value from the reference object to an instance of the value type on the thread stack.
After these 2 steps, it can be considered as reciprocal operation with boxing. Strictly speaking, unboxing does not affect performance, but the operation of copying data after that affects performance as one of the boxing operations does.

11,

All types of NET are inherited from the base class ES179en.Object, including the most common base types: int, byte, short, bool, etc., meaning that everything is an object.

If you declare that all these types are allocated in the heap (HEAP), it is extremely inefficient! (The reasons for this and the difference between heap and stack will be discussed in a separate article!)
How can NET solve this problem? It is by dividing types into value types (value) and reference types (regerencetype) that

Value types and reference types defined in C#

Value types: original type (Sbyte, Byte, Short, Ushort, Int, Uint, Long, Ulong, Char, Float, Double, Bool, Decimal), enumeration (enum), structure (struct)
Reference types: class, array, interface, delegate, string, and so on
A value type allots memory on the stack and initializes it as it is declared to ensure that the data is not NULL.
Reference type is allocated memory in the heap, initialized to null, reference type is required GARBAGE COLLECTION to reclaim memory, value type is not needed, beyond the scope of action, the system will automatically release!
The following is the definition of packing and unpacking!
Boxing implicitly converts a value type to a reference type object. Such as:


int i=0;
Syste.Object obj=i;

This process is called packing! Is to pack i!
Unboxing is the conversion of a reference object into an arbitrary value! Such as:

int i=0;
System.Object obj=i;
int j=(int)obj;

In this process, the first 2 sentences are to box i, the second sentence is to unbox obj!


Related articles: