Six important concepts in. NET: Stack, heap, value type, reference type, packing and unpacking,. net packing
Content Guide
- Overview
- What happens when you declare a variable?
- Stack and stack
- Value Type and reference type
- What are value types and reference types?
- Packing and unpacking
- Packing and unpacking performance problems
I. Overview
This article describes six important concepts: heap, stack, value type, reference type, packing and unpacking. This article will first explain the changes that occur inside the system after you define a variable, and then shift the focus to storage: heap and stack. Then, we will discuss the value type and reference type, and explain the important basic content about these two types.
This article uses a simple code to demonstrate the performance impact of the packing and unpacking processes. Please read carefully.
2. What happens when you declare a variable?
When you define a variable in A. NET application, some memory blocks will be allocated to it in RAM. The memory has three things: the name of the variable, the Data Type of the variable, and the value of the variable.
The above briefly describes what happens in the memory, but the type of memory that your variables will be allocated depends on the data type. There are two types of memory that can be allocated in. NET: Stack and heap. In the following sections, we will try to understand the two types of storage in detail.
Iii. Storage: heap and stack
To understand the stack and stack, let's use the following code to understand what happened behind the scenes.
1234567891011 |
public void Method1() { // Line 1 int i=4; // Line 2 int y=2; //Line 3 class1 cls1 = new class1(); } |
There are only three lines of code. Now we can know how to execute the code in one row.
- Line 1: When this Line is executed, the compiler allocates a small block of memory on the stack. The stack is responsible for tracking whether your application has the need for running memory.
- Line 2: now we will perform step 2. Just like the stack name, it overwrites a small memory allocation here to the top of the memory allocation in the first step. You can think of stacks as a stacked room or box. In the stack, the distribution and release of data are all performed through the LIFO (Last In First Out), that is, the logic rules for advanced and later release. In other words, the data items that first enter the stack may finally exit the stack.
- Line 3: In the third row, we create an object. When this row is executed,. NET will create a pointer in the stack, and the actual object will be stored in a memory area called "Heap. Heap does not monitor the running memory. It is only a bunch of objects that can be accessed at any time. Unlike stack, stack is used for dynamic memory allocation.
- Another important point to note here is that the object's reference pointer is allocated on the stack. For example, the declared statement Class1 cls1 does not actually allocate memory for the Class1 instance. It only creates a reference pointer for the variable cls1 on the stack (and sets its default position to null ). It allocates memory for objects on the heap only when it encounters the new keyword.
- When you exit the Method1 method (the fun): the execution of the control statement begins to exit the method body, and all memory space allocated for the variable on the stack will be cleared. In other words, in the preceding example, all int-type variables will be output from the stack one by one in the "LIFO" and later in the first-in-first-out mode.
- Note that the memory block in the heap will not be released at this time, and the memory block in the heap will be cleaned up later by the garbage collector.
Many of our developers are wondering why there are two different types of storage? Why can't we allocate all the memory blocks to one type of storage?
If you observe carefully enough, the basic metadata type is not complex and they only save values like 'int I = 0. The object data type is complicated. They reference other objects or other basic metadata types. In other words, they save references to multiple other values and these values must be stored in memory one by one. The object type requires dynamic memory, while the primitive type requires static memory. If dynamic memory is required, it will allocate memory to it on the heap. On the contrary, it will be allocated on the stack.
Iv. Value Type and reference type
Now that we have understood the concept of stack and stack, it is time to understand the concept of value type and reference type. The Value Type stores data and memory in the same location, while a reference type has a pointer to the actual memory area.
We can see that the value of an integer data type named I is assigned to another Integer Data Type named j. Their values are stored on the stack.
When we assign a value of the int type to another value of the int type, it actually creates a completely different copy. In other words, if you change one value, the other will not change. Therefore, the data types of these types are called "value types ".
When we create an object and assign it to another object, they all point to the same area of memory as shown in the code segment. Therefore, when we assign obj to obj1, they all point to the same area in the heap. In other words, if we change any of them at this time, the other will be affected, which also shows why they are called "reference type ".
5. What are value types and reference types?
In. NET, whether a variable is stored in the stack or heap depends entirely on its data type. For example, 'string' or 'object' belongs to the reference type, while other. NET base metadata types are allocated to the stack. It details the values and references in the. NET preset types.
6. packing and unpacking
Now you have a lot of theoretical basics. Now, it is time to understand how to use the above knowledge in actual programming. The biggest significance of an application is to understand the performance consumption problems in the process of moving data from Stack to stack, and vice versa.
Consider the following code snippet. When we convert a value type to a reference type, the data will be moved from the stack to the heap. On the contrary, when we convert a reference type to a value type, the data will also be moved from the heap to the stack.
System performance is inevitably affected, whether it is moving from Stack to stack or from Stack to stack.
As a result, two new terms emerged: when the data is converted from the value type to the reference type, it is called "Packing", and the process from the reference type to the value type is changed to "unpacking ".
If you compile the above Code and view it in ILDASM (an IL decompilation tool), you will find out what it looks like in the IL code. The IL code generated after the sample code is compiled is displayed.
VII. packing and unpacking performance problems
To understand the performance impact of packing and unpacking, We cyclically run the two function methods shown 10000 times. The first method contains the packing operation, while the other method does not. We use a Stopwatch object to monitor time consumption.
The method with a boxing operation took 3542 milliseconds to complete, while the method without a boxing operation only took 2477 milliseconds, a full difference of more than 1 second. This value also increases with the increase in the number of loops. That is to say, we should try to avoid packing and unpacking. In a project, if you need to pack and pack, consider whether it is absolutely essential. If not, try not to use it.
Although the above Code segment does not show the box-breaking operation, the effect is also applicable to the box-breaking operation. You can write code to split the box and use Stopwatch to test the time consumption.
Source: Shivprasad koirala