. NET Framework-memory management story and variable creation and destruction

Source: Internet
Author: User
Tags finally block

Objective

The. NET runtime handles the recycling of managed resources automatically through the garbage collector, and unmanaged resources require manual encoding processing. Understand how memory management works to help improve the speed and performance of your applications. Talk less, cut to the chase. The main concepts are described below:


Concept

 memory : Also known as virtual memory , or virtual address space , Windows uses a virtual addressing system that automatically maps available memory addresses to physical addresses in hardware memory in the background. As a result, each process on a 32-bit processor can use 4GB of memory to hold all parts of the program, including executable code (EXE files), all the DLLs that the code loads, and the contents of all the variables that the program uses to run.
Memory Stacks
In the virtual memory of the process, the existence of a variable must have a nested region of the lifetime.
Memory Heap
In the virtual memory of the process, the data remains available for a long time after the method exits.
Managed Resources
Resources that the garbage collector can handle automatically in the background
Unmanaged Resources
Requires manual coding, through destructors, finalize,idisposable,using and other mechanisms or methods to process the resources.

Memory stacks

Value type data is stored in the memory stack, the instance address value of the reference type is also placed in the memory stack (see discussion of Memory heap), and the memory stack works through the following code:

{//BLOCK1 begins    int A;        Solve something    {//block2 start       int b;              Solve something else    }//block2 end}//block1 End

The above code Note 2 points:
1) The scope of variables in C #, followed by declared after the scope, after the declaration of the first out of scope, that is, B is released, a after release, the release order is always the opposite of the order in which they allocate memory.
2) b is in a separate block scope (Block2), and the block name where A is block1is nested with Block2.
 
Please see below:



Stack memory management, a stack pointer is always maintained, which always points to the next available address in the station area, named SP, and assumes it points to an address numbered 1000.
Variable a first into the stack, assuming that the machine is 32-bit, the int is 4 bytes, that is, 997~1000, after the stack, the SP points to 996, the visible memory stack growth direction from the high address to the low address direction.
Then b into the stack, occupying 993~996,sp pointing to 992. When the block Block2 is exceeded, variable B immediately releases the storage on the memory stack, the SP adds 4 bytes, and points to 996.
Go outward, beyond the block block1 , the variable a is immediately released, when the SP added 4 bytes, pointing to the original initial address 1000, and then back into the stack, these addresses are again occupied, and then released, the cycle.

Memory heap

Although the stack has very high performance, it is still less flexible for all variables because the lifetime of the variables on the memory stack must be nested. In many cases, this requirement is too harsh because we want some data to be available for a long time after the method exits.
As long as the heap storage space is requested with the new operator, the data declaration period delay is satisfied, such as all reference types. Use the managed heap in. NET to manage the data on the memory heap.
The managed heap in. NET differs from the heap used by C + +, which works under the control of the garbage collector, while the C + + heap is low-level.
Since data of reference types are stored on the managed heap, how are they stored? Take a look at the following code
 

void Shout () {   Monkey xingxing;//Monkey class   xingxing = new Monkey ();}

In this code, assume two classes Monkey and Aimonkey, where the Aimonkey class extends the Monkey object.
  
  here, we call monkey an object, called Xingxing, as an instance of it.
  
First, declare a monkey reference xingxing, allocate storage space on the stack for this reference, and remember that this is only a reference, not an actual monkey object. Remember this is very important!!!
Then look at the 2nd line of code:

xingxing = new Monkey ();

It completes the operation: first, it allocates the memory on the heap to store the Monkey object, note!!! This is a real object and it is not an address that occupies 4 bytes!!! Assuming that the Monkey object occupies 64 bytes, these 64 bytes contain the fields of the monkey instance, and some information in. NET to identify and manage instances of the Monkey class. These 64 bytes are actually allocated on the memory heap, assuming that the address on the memory heap is 1937~2000. The new operator returns a memory address, assumed to be 997~1000, and assigns a value to xingxing. As shown below:



Remember one point:
Unlike the memory stack, the memory on the heap is allocated up, from the low address to the high address.
From the above example, it can be seen that the process of establishing a reference instance is more complex and more expensive than establishing a value variable. So what is the advantage of spending so much? reference data type where is the power???
 
Take a look at the following code:

{//block1    Monkey xingxing; Monkey class    xingxing = new Monkey ();    {//block2      Monkey jingjing = xingxing; Jingjing also references the Monkey object      //do something    }    //jinjing out of scope, it is removed from the stack    //Now only xingxing is still referencing monkey}// Xingxing out of scope, it is removed from the stack//is not currently referenced in Monkey

Assigning the value of a reference instance to another instance jingjing of the same type xingxing the result that there are two references to the same object in memory monkey. When an instance goes out of scope, it is removed from the stack, but the data that references the object remains in the heap until the program terminates, or the garbage collector reclaims its location, and only that data is no longer referenced by any instance, it is deleted!
Give me a simple example of a practical application reference:
  

Fetching data from the interface into the list list<person> persons = Getpersonsfromui ();//retrieve these persons from dblist<person> Personsfromdb = Retrievepersonsfromdb ();//do something to Personsfromdbgetsomethingtopersonsfromdb ();

Can you tell me about the change of Personsfromdb in time?
No!
Please look at the following code changes:

Fetching data from the interface into the list list<person> persons = Getpersonsfromui ();//retrieve these persons from dblist<person> Personsfromdb = Retrievepersonsfromdb (); int cnt = persons. count;for (int i=0;i<cnt;i++) {  persons[i]= personsfromdb [i];}//do something to Personsfromdbgetsomethingtopersonsfromdb ();

Once modified, the data responds immediately to the interface. Because persons is bound to the UI, all modifications on persons can naturally respond immediately.
This is where the power of reference data types is, in C #. This feature is widely used in net. This shows that we can have very strong control over the lifetime of the data, because as long as we keep a reference to the data, that data is definitely on the heap!!!
This also indicates that the stack-based instance does not match the lifetime of the heap-based Object!

Garbage collector GC

Fragments are formed on the memory heap. The net garbage collector compresses the memory heap, moves the object, and modifies all referenced addresses of the object, which is one of the differences between the managed heap and the unmanaged heap.
. NET's managed heap only needs to read the value of the heap pointer, but the unmanaged old heap needs to traverse the address list to find a place to place the new data, so the. NET to instantiate objects much faster.
The first part of the heap is called the No. 0 generation, which resides in the most recent object. The old objects left over in the No. 0 generation garbage collection are placed on the corresponding parts of the 1th generation, and then recursively go down ...

Connecting link

The above section is the memory management portion of the managed resources, which are made in the background. NET is executed automatically. The following is a look at the memory management of unmanaged resources, such as the UI handle, the network connection, the file handle, the image object, and so on. NET mainly through three kinds of mechanism to do this thing. Respectively, the destructor, the IDisposable interface, and the combination of the two methods, in order to achieve the best result of processing. Let's look at the following separately.

Destructors

When the C # compiler compiles a destructor, it implicitly compiles the destructor code into code equivalent to the Finalize () method, and determines the Finalize () method that executes the parent class. Look at the following code:

public class person{   ~person ()   {      //destructor implementation   }}

~person () C # code for the IL generated by the destructor:

protected override void Finalize () {   try   {      //destructor implementation   }   finally   {     base. Finalize ();   }}

In the finally block, ensure that the parent class's Finalize () must be called.
C # destructors are much less used than C + + destructors because their problem is uncertainty. When a C + + object is destroyed, its destructor is immediately executed. However, because C # uses the garbage collector, it is not possible to determine when the destructor of a C # object executes. If an object consumes valuable resources and needs to release resources as soon as possible, you cannot wait for the garbage collector to release it.
The first time the destructor is called, the object that has the destructor needs to call the destructor a second time before the object is actually deleted. If you use destructors frequently, the impact on performance is significant.

IDisposable interface

In C #, it is recommended to use the IDisposable interface instead of a destructor, which provides a deterministic mechanism for releasing unmanaged resources, rather than when the uncertainty is performed like a destructor.
Assuming that the person object relies on some external resources and implements the IDisposable interface, you can do this if you want to release it:

Class person:idisposable{public  void Dispose ()  {    //implementation  }}person xingxing = new Person ( );//dom somethingxingxing. Dispose ();

If an exception occurs during the processing of the above code, the code does not release xingxing, so it is modified to:

Person xingxing = null;try{   xingxing  = new Person ();   Do something}finally{   if (xingxing!=null)    {        xingxing. Dispose ();    }}

C # provides a syntactic sugar, called a using, to simplify the above operation.

using (person xingxing = new Person ()) {  //do something}

The semantics of using here are different from the normal reference class libraries. Using the function here, just simplifies the code, this syntax sugar can be used sparingly!!!
In summary, the object that implements IDisposable must call the Dispose () method manually when releasing an unmanaged resource. Therefore, once forgotten, it will cause a resource leak. As shown below:

                Image Backimage = this. BackgroundImage;                                if (backimage! = null)                {                    backimage.dispose ();                    Sessiontoimage.deleteimage (_imagefilepath, _imagefilename);                                        This. BackgroundImage = null;                }

In the above example, Backimage has determined that it is no longer used, and backimage is being read from the physical disk via Image.FromFile (Fullpathway), unmanaged resources, so Dispose () is required, The process of reading the image so that it is closed. If you forget to write Backimage.dispose (), it will cause a resource leak!

The 2 mechanisms of combining destructors and IDisposable

In general, the best way is to implement two mechanisms to obtain the advantages of both mechanisms. Because the Dispose () method is called correctly, the implementation destructor is used as a security mechanism in case the Dispose () method is not called. Refer to a mechanism for releasing managed and unmanaged resources in combination of two methods:
  

public class person:idisposable{   private bool isdisposed = false;   Implement IDisposable interface Public   void Dispose ()   {         //True to clean managed and unmanaged Resources      Dispose (true);            Tells the garbage collector not to call the destructor out of the      GC. SuppressFinalize (this);   }      protected virtual void Dispose (bool disposing)   {         //isdisposed: Whether the object has been cleaned out      if (!isdisposed)      {                if (disposing)          {                      //clean up Managed resources           }                      //Clean Up Unmanaged Resources       }       isdisposed = true;   }   ~person ()   {        //false: Only cleanup of unmanaged Resources     //Managed resources after invocation is a separate thread of the garbage collector Finalize ()     Dispose (false);}   }

When the user of this object calls the Dispose () method directly, for example

Person xingxing = new person ();//do Somethingperson. Dispose ();

The IDisposable.Dispose () method is called, specifying that all resources related to the object, including managed and unmanaged resources, should be cleaned up.

If the Dispose () method is not called, the managed and unmanaged resources are disposed of by the destructor.

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.