C # Memory Management: Stack, managed heap, and pointer

Source: Internet
Author: User
Tags hosting

[Transfer]
In a 32-bit Windows operating system, each process can use 4 GB of memory, thanks to the virtual addressing technology, which stores executableCode, The DLL andProgramIn C #, the virtual memory contains two storage variable regions. One is called a stack, the other is called a managed heap, and the other is called a managed heap.. NET is different from other languages in that stack stores value-type data, while the hosted heap stores reference types such as classes and objects, and is controlled and managed by the garbage collector. In the stack, once a variable exceeds the usage range, the memory space used by the variable will be reused by other variables. In this case, the stored values in the space will be overwritten by other variables and will no longer exist, but sometimes we want these values to still exist, which requires the managed heap to implement. We use several pieces of code to describe how it works. Suppose we have defined a class class1:

Class1 object1;

Object1 = new class1 ();

The first sentence defines a class1 reference. In essence, it only allocates a 4-byte space in the stack. It will be used to save the house and then instantiate the address of the object in the managed heap, in Windows, this requires four bytes to represent the memory address. The second instantiation of the object1 object is actually a specific object in the managed heap that has a memory space to store class class1. Assume that this object requires 36 bytes, then object1 points to the address starting with a 36-byte continuous memory space in the managed heap. We can also see why the C # compiler does not allow the use of uninstantiated objects, because this object does not exist in the managed heap. When the object is no longer in use, the referenced variable stored in the stack will be deleted. However, from the above mechanism, we can see that the referenced object still exists in the managed heap, when the space is released, it depends on the garbage collector rather than the reference variable that has no scope.

You may have had this experience when using a computer: After a computer is used for a long time, the program runs slowly. One of the important reasons is that there are a large number of memory fragments in the system, it is because the program repeatedly creates and releases variables in the stack. Over time, the available variables will no longer be contiguous memory space in the memory. To address these variables, the system overhead will also be increased. In. net. This situation will be greatly improved because with the spam collector, the spam collector will compress the memory space of the managed heap, ensure that the available variables are in a continuous memory space, and change the address in the referenced variable in the stack to a new address, which will bring additional system overhead, however, the benefits will offset this impact, and the other advantage is that programmers will no longer spend a lot of time thinking about the leakage.

Of course, in the C # program, there are not only variables of the reference type, but also objects of the value type and other managed heaps that cannot be managed. If the file name handle, network connection, and database connection, the release of these variables still needs to be done by the programmer through the Destructor or idispose interface.

On the other hand, in some cases, the C # program also needs to pursue speed. For example, if you still use traditional classes to operate on an array containing a large number of Members, will not get good performance, because the array in C # is actually system. array instances will be stored in the managed heap, which will cause a lot of extra operations to the operation, in addition to the spam collector, the managed heap is compressed, the reference address is updated, and the list of managed heap information is maintained. Fortunately, C # can also use the C ++ programmer's usual favorite method to encode Unsafe code, and use pointers in code blocks marked as unsafe, this is no different from using pointers in C ++. variables are stored in the stack. In this case, stackalloc can be used to declare an array, for example, declare an array with 50 double types:

Double * pdouble = stackalloc double [50]

Stackalloc allocates 50 double-type memory space to the pdouble array in the stack. You can use pdouble [0] And * (pdouble + 1) to operate the array, like in C ++, when using pointers, you must know what you are doing and ensure that the correct memory space is accessed. Otherwise, unexpected errors may occur.

Understanding how managed stacks, stacks, garbage collectors, and insecure code work will help you become a really good C # programmer.

Each thread in the process has its own stack, which is the address area left when a thread is created. Our "stack memory" is here. As for the "Heap" memory, I personally think that when the new definition is not used, the heap should be free space without "retained" and not "submitted, the new function is to retain (and submit?) in these free spaces ?) Out of an address range
A stack is a storage area created for a thread by the operating system when a process is created or by a thread (in a multi-threaded operating system). The stack has a FIFO

The Filo feature allows you to specify the size of the required stack during compilation. In programming, for example, in C/C ++, all local variables are allocated memory space from the stack. In fact, they are not allocated, but they can be used up from the top of the stack, when you exit the function, you can destroy the stack content by modifying the stack pointer, so the speed is the fastest.
Heap is a process in which an application requests the operating system to allocate its memory when running, c/C ++ allocates heap with malloc/new requests respectively, and destroys memory with free/Delete. Since memory allocation managed by the operating system takes up time for allocation and destruction, it is much less efficient to use the heap! But the advantage of heap is that it can be done very much. C/C ++ does not initialize the heap allocated.
In Java, apart from simple types (INT, Char, etc.), memory is allocated in the heap, which is also a major cause of slow programs. However, unlike C/C ++, heap memory allocation in Java is automatically initialized. All objects in Java (including wrapper integer of INT) are allocated in the heap, but the reference of this object is allocated in the stack. That is to say, when an object is created, the memory is allocated from both locations. The memory allocated in heap actually creates this object, the memory allocated in the stack is just a pointer (reference) pointing to the heap object.
Among all. NET technologies, the most controversial one is probably garbage collection (GC. As an important part of the. NET Framework, hosting heap and garbage collection mechanisms are unfamiliar to most of us. In this article Article We will discuss the managed heap and what benefits you will get from it.
Why is heap managed?
The. NET Framework contains a managed heap. All. NET languages use it when allocating reference type objects. Lightweight objects such as value types are always allocated to the stack, but all class instances and arrays are generated in a memory pool. This memory pool is a managed heap.
Basic Garbage Collector Algorithm Simple:
● Mark all managed memory as spam
● Search for memory blocks being used and mark them as valid
● Release all unused memory blocks
● Organize the heap to reduce fragments
Managed heap Optimization
It seems very simple, but the steps actually taken by the garbage collector and other parts of the heap management system are not trivial, and they often involve the optimization design to improve performance. For example, garbage collection traversing the entire memory pool has a high overhead. However, research shows that most objects allocated on managed stacks only have a short lifetime, so the heap is divided into three segments, called generations. The newly allocated object is placed in generation 0. This generation is the first to be recycled-in this generation, it is most likely to find memory that is no longer in use, because it is small (small enough to be put into the L2 cache of the processor ), therefore, the recovery in it will be the fastest and most efficient.
Another optimization operation for hosting heap is related to the locality of reference rule. This rule indicates that objects allocated together are often used together. If the objects are in a tight position in the heap, the high-speed cache performance will be improved. Because of the nature of hosting heap, objects are always allocated on consecutive addresses, and managed heap is always compact. As a result, objects are always close to each other and never get far apart. This is in stark contrast to the unmanaged code provided by the standard heap. In the standard heap, the heap can easily become fragments, and the objects allocated together are often far away from each other.
Another optimization is related to large objects. Generally, large objects have a long lifetime. When a large object is generated in the. NET managed heap, it is allocated in a special part of the heap, which will never be organized. Because the overhead of moving large objects exceeds the performance that can be improved by sorting out these sub-stacks.
External resources
The garbage collector can effectively manage resources released from the managed heap, but the resource recycling operation is only executed when the memory is insufficient and a collection action is triggered. So how does a class manage limited resources such as database connections or window handles? Wait until the garbage collection is triggered and then clean up the database connection or file handle is not a good method, which seriously reduces the system performance.
All classes with external resources should execute the close or dispose method when these resources are no longer used. Starting from beta2 (all beta2 in this Article refers to. NET Framework beta2, which is not explicitly stated), The dispose mode is implemented through the idisposable interface. This will be discussed later in this article.
The class that needs to clear external resources should also implement a finalizer operation ). In C #, the preferred method to create a termination operation is to implement it in the destructor, while in the framework layer, the termination operation is implemented by reloading the system. Object. Finalize method. The following two methods to terminate an operation are equivalent:
~ Overduebooklocator ()
{
Dispose (false );
}
And:
Public void finalize ()
{
Base. Finalize ();
Dispose (false );
}
In C #, terminating the operation in both the Finalize method and the Destructor will result in errors.
Unless you have enough reason, you should not create the Destructor or finalize method. Terminating the operation will reduce the system performance and increase the memory overhead during the execution period. At the same time, due to the method in which the operation is terminated, you cannot guarantee when the operation will be terminated.
Details of memory allocation and garbage collection
After having a general impression on GC, let's discuss details about the allocation and recycling work in the managed heap. Hosting heap looks like a traditional heap in C ++ programming that we are already familiar. In the traditional heap, the data structure is used to using large idle memory. Finding memory blocks of a specific size is a very time-consuming task, especially when the memory is full of fragments. In the managed heap, memory is grouped into consecutive arrays, and pointers always move between the used memory and the unused memory. When the memory is allocated, the pointer simply increments. One advantage of this is that the efficiency of the allocation operation has been greatly improved.
When objects are allocated, they are initially placed in generation 0. When the size of generation 0 is about to reach its upper limit, a recycling operation executed only in generation 0 is triggered. Because the size of generation 0 is small, this is a very fast GC process. The result of this GC process is to completely refresh generation 0. Objects that are no longer in use are released. objects that are actually in use are organized and moved to generation 1.
When the size of Generation 1 is close to its upper limit as the number of objects migrated from generation 0 increases, A collection action is triggered to execute the GC process in generation 0 and generation 1. As in generation 0, objects that are no longer in use are released, used objects are organized and moved into the next generation. The main goal of most GC processes is generation 0, because in generation 0, there may be a large number of temporary objects that are no longer in use. This process has a high overhead for the collection process of generation 2, and will be triggered only when the GC process of generation 0 and generation 1 cannot release enough memory. If the GC process of generation 2 still cannot release enough memory, the system will throw an outofmemoryexception
The garbage collection process for objects with termination operations is slightly more complex. When an object with a termination operation is marked as spam, it is not immediately released. Instead, it will be placed in a Finalization queue, which creates a reference for this object to prevent this object from being recycled. The background thread executes their respective termination operations for each object in the queue, and deletes the object that has already executed the termination operation from the termination queue. Only objects that have been terminated will be deleted from the memory during the next garbage collection process. One consequence of this is that the object waiting for termination may be moved into a higher-level generation before it is cleared, thus increasing the delay time for it to be cleared.
The object that needs to terminate the operation should implement the idisposable interface so that the client program can quickly perform the termination action through this interface. The idisposable Interface contains a method called dispose. This interface introduced by beta2 is implemented in a mode that has been widely used before beta2. Essentially, an object that needs to terminate an operation exposes the dispose method. This method is used to release external resources and suppress termination operations, as shown in the following program snippet:

 
Public ClassOverduebooklocator: idisposable
 
{
~ Overduebooklocator ()
 
{
 
Internaldispose (False);
 
}
 
Public VoidDispose ()
{
 
Internaldispose (True);
 
}
 
Protected VoidInternaldispose (BoolDisposing)
{
 
If(Disposing)
 
{
 
GC. suppressfinalize (This);
 
// Dispose of managed objects if disposing.
}
 
// Free external resources here
 
}
 
}
 
 
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.