Original:---C # heap vs Stack (Part One)
Objective
This article mainly explains the use of C # language in memory heap, stack, so that readers can better understand the value type, reference type and line stacks, managed heap.
First thanks to the original Matthew Cochran has brought us a very good article, and with a large number of illustrations, to help us better understand the call between the stack, this article is based on the author's original content of the streamlining and join my personal understanding and comments in this regard.
Finally thanks to the blog Tian Zhilao, when I search the stack internal use, search the author's article, draw a lot of useful knowledge, and translation is very good. The only drawback may be the only translation of Matthew Cochran the first article of this series, and ignored the following several, resulting in a slightly incomplete content, so I will continue to complete the follow-up work, for everyone to answer questions.
Here's why the author wrote this article:
Although with the. Net Framework we don't have to worry about memory management and garbage collection issues, but we still have to remember memory management and garbage collection in order to optimize the program. Moreover, having a basic concept of how memory management works will help us explain the behavior of variables in every program we write.
Note: limited to my English comprehension skills, as well as technical experience, if there is a mistake in the text, please do not hesitate to point out.
Directory
C # Stack contrast (Part one)
C # Stack contrast (part)
C # Stack contrast (Part three)
C # Stack contrast (Part Four)
Stack vs heap: The difference
The stack is responsible for tracking what is executed in our code (or what is called). The heap is responsible for tracking our objects (our data, of course, is "data" in most cases, which I will discuss later).
Note: Stacks are similar to a container for code execution, whereas heaps are similar to containers that hold data.
Think of the stack as a series of boxes, one falling on top. Each time we invoke a method (called a Frame), we observe what is going on in our code by stacking the box on top of the box. In fact, we can only use the top-most box in the stack. When we have finished processing the topmost box (the method and function we have executed), we discard it and continue to use the box at the top. The heap is similar to stacks, except that the purpose of the heap is to keep the information (in most cases not tracing the execution code) so that at any moment our heap can be accessed. With heaps, we will not have as many access constraints as stacks. The heap is more like a bunch of laundry that we haven't had time to clean up in bed, we can get the clothes we want quickly. And the stack is more like a pile of shoe boxes in the closet, and we take out the top shoe boxes in order to get the shoes in the box below.
Note: The online search for two images to replace the author's pictures, this will be more vivid. The stack is on the left and the right is the heap.
The stack is self-sustaining, which means it basically only has to do with its own memory management. When the box at the top of the stack is no longer in use, it is discarded immediately. Heap, on the other hand, must be concerned about the garbage collection problem, which mainly deals with how to keep the heap tidy (no one likes to mess up dirty clothes, smelly ~ ~ ~ ~).
Note: The contents of the stack are freed after each instruction, so there is no need to focus on resource leaks, and the heap needs to reclaim resources that are no longer in use when the GC is uncertain, maintaining and focusing on performance issues.
What exactly happened on the stack.
We have four main types in our heap or stack: value types, reference types, pointer types, and directives.
- Value type:
In C #, all value types inherit from the abstract class System.ValueType.
Note: System.ValueType inherits from System.Object, and overrides the. ToString () method to prevent boxing problems in some cases.
- bool
- Byte
- Char
- Decimal
- Double
- Enum
- Float
- Int
- Long
- SByte
- Short
- struct
- UInt
- ULong
- UShort
2. Reference type:
In C #, reference types, such as the following, inherit from System.Object, except, of course, Object itself.
- Class
- Interface
- Delegate
- Object
- String
3. Pointer type:
The third type that is placed in our memory management is a reference type, which is what we often call pointers. We do not explicitly use pointers, they are resources that are managed by the CLR. Pointers (or references) are different from reference types when we discuss reference types, which means that we use pointers using reference types. One pointer is a large chunk of memory pointing to another memory space. A pointer occupies space as if we were placed in a heap or stack, and its value is an address or null.
4. Instruction Type:
Later, we'll analyze it in a later article.
How do I infer if a type is on a heap or on a stack?
Here, we have two golden laws:
- Reference types are always created on the heap, very simple, right?
- Value types and pointer types are always created where it is declared. This is a bit complicated and needs to know how the stack works.
Stack, as we said earlier, is responsible for tracking the execution of code in each thread (or being called). You can think of it as a thread state and each thread has its own state. When our code calls execute a method that starts executing an instruction that has been JIT-compiled and survives in the method table (live on the), it also places the parameters online stacks. Then, when we enter the method body and take the parameter execution method, the instruction will be referred to the top of the stack.
Here's a piece of code to illustrate:
1 Public int Addfive (int pValue)2{3 int result; 4 5 ; 5 return result; 6 }
This is what happens on the stack. It must be remembered that what we are observing is already on the stack: we execute the method and the method parameters are placed on the stack, and later we talk about the parameter details.
The Addfive method in this diagram does not exist in the stack, just for illustrative purposes.
Next, the command executes to the Addfive () method that exists in our type table, and if the method is executed for the first time, the JIT executes once.
When the method executes, we need some memory as the "result" variable, and this variable will be created on the stack, such as:
The method finishes executing and returns the result. Such as:
All memory created on the stack will be cleaned up by pointing the pointer to the available memory address at the beginning of addfive ().
In this example, our "result" variable will be placed in the stack. In fact, each time the value type is declared with the method body, it is placed in the stack.
Value types are now sometimes placed in the heap. Keep in mind this rule that the value type depends on where it is declared and whether it is on the heap or on the stack. If a value type is declared outside the method body, but inside the reference type, it will be wrapped in the reference type and created on the heap.
Examples are as follows:
If we have the following Myint class (the class is naturally a reference type)
Public class myint{ publicint myvalue;} Execute as follows: public MyInt addfive (int pValue) {new MyInt () ; 5 ; return result;}
Just like just now, threads begin to hold line methods and parameters on the thread stack, such as:
It's more interesting now. Because Myint is a reference type, the myint type is placed in the heap and referenced by a pointer placed on the stack (pointing), such as:
After Addfive () is executed, we will clean up the stack, such as:
We only have one lonely object in the heap (there will be no pointers in the stack pointing to Myint in the heap), such as:
This is the stage where the GC shows its strength. When we reach a certain memory bottleneck we need more space in the heap when the GC comes out. The GC stops all running threads (stop completely), finds all the objects that are not referenced in the heap, and deletes them. The GC will reorganize all the objects in the heap to get space and adjust all the pointers in the heap as well as the stack. As you might expect, this will cost a lot of performance, so now you can see how important it is to focus on the stack when you're writing high-performance code.
Note: 1. GC recycling generally occurs when program memory is not sufficient, otherwise it does not occur unless manually invoked. 2. Manually invoking the GC enables a forced "try" to reclaim resources. All the resources in the 3.GC are "generations", each time the object in the heap is also referenced, if there is a current "generation" number plus one, or minus one, GC reclaim "generation" number of the smallest resources, which explains why even after I manually call the Gc.collect () method, The object is still not being recycled immediately. 4. Frequent calls to Gc.collect () can cause frequent thread interruptions, which can severely impact performance.
All right, great, what's the matter with me?
That's a good question.
When we use reference types, we are dealing with pointers of this type rather than referencing (the actual method, type) itself; When we use value types, we are using the type itself. It's confusing, isn't it?
Again, the following example is a good illustration of the problem:
Public int returnvalue ()
{ intnewint(); 3 ; int New int (); = x; 4 ; return x;}
The final result is 3. It's very simple, isn't it?
public class myint{ public int myvalue;} public int ReturnValue2 () {MyInt x = new MyInt (); X.myvalue = 3 ; MyInt y = new MyInt (); Y = X; Y.myvalue = 4 ; return X.myvalue;}
What is the return value? The answer is 4!
Why? How does the X.myvalue change to 4? Take a look at what we're doing and whether it makes sense:
Public int returnvalue () { int3; int y = x; 4 ; return x;}
Note: A value type is a pass-through value, not a pass-through reference, such as:
In the next example, we don't get "3" because both X and Y are variables that point to the same heap object.
Public int ReturnValue2 () { MyInt x; 3 ; MyInt y; = x; 4 ; return X.myvalue;}
Note: In practice, the reference type is the same object that points to the heap.
Hopefully this will allow you to have a better understanding of value types and reference types through C # code and understand the usage of pointers and where to use them.
In the next section, we'll talk a bit more about memory management, especially if we discuss method parameters.
Summarize
- Heap and stack concepts and differences: In-memory stack is mainly responsible for processing the command in the thread, and is read and executed as a stack stack, the heap is mainly the storage method body and data, similar to the bed scattered clothes, can be randomly read.
- Value types differ from reference types: reference types always exist on the managed heap, and the value types depend on where they are declared.
- Garbage collection on heaps and stacks: the stack has a self-maintenance feature, and releasing the statement immediately does not cause a resource leak. The heap is GC-recoverable and conforms to the rules of GC recycling, and many of the contents of the heap are not recycled until the program exits, most likely inadvertently leaving a reference to the content, which can seriously affect performance.
- Value types and reference types are handled differently when content is changed: value types perform content copies, and reference types always change the referenced content, which results in inconsistent behavior between the two.
---C # heap vs Stack (Part One)