Deep understanding of. NET memory recovery mechanism

Source: Internet
Author: User

Reproduced from: http://www.chinamacro.com/blog/visit_detail.aspx? Blogid = 177
The. Net platform provides many new features that help programmers produce more efficient and stable code. One of them is the garbage collector (GC ). This article will explore this function in depth to learn how it works and how to write code to better use the features provided by this. Net platform.

Memory recovery mechanism in. Net

The garbage collector is used to manage the memory allocation and release of applications. Before the appearance of the garbage collector, the programmer needs to apply for memory space from the system when using the memory. Some languages, such as Visual Basic, can automatically apply for memory space from the system. However, in languages such as Visual C ++, programmers are required to apply for memory space in program code. If the programmer forgets to release the memory after using the memory, it will cause memory leakage. But with the garbage collector, programmers do not have to worry about whether the objects in the memory are released after they leave the lifetime. When an application is running, the garbage collector sets a managed heap. The managed heap is similar to the heap in C language, but the programmer does not need to release objects from the managed heap, and the storage of objects in the managed heap is continuous.

Every time a developer creates an object using the new operator, the runtime allocates memory for the object from the managed heap. The newly created object is placed after the last created object. The garbage collector saves a pointer that always points to the memory space after the last object in the managed heap. When a new object is generated, the runtime knows where the new object should be stored in the memory. At the same time, developers should put objects of the same type together. For example, when developers want to write data to the database, they need to create a connection object, a Command object, and a DataSet object. If these objects are placed in adjacent areas of the managed heap, they can be accessed very quickly.

When the pointer of the garbage collector points to the memory space outside the managed heap, the garbage in the memory needs to be recycled. In this process, the garbage collector first assumes that all objects in the managed heap need to be recycled. Then it looks for the object referenced by the root object in the managed heap (the root object is a global, static or active local variable, and the object pointed to by the register ), add them to the list of valid objects, and search for objects that have been searched for to see if any objects have been referenced by new valid objects. After the Garbage Collector checks all objects, there is a list of objects directly or indirectly referenced by the root object and the root object, other objects that are not in the table are recycled from the memory.

When an object is added to the managed heap, if it implements the finalize () method, the garbage collector adds a pointer to the object in its Finalization List. When the object is recycled, the garbage collector checks the end list to see if the finalize () method of the object needs to be called. If yes, the garbage collector adds the pointer to the object to a worker queue, which stores the objects that are going to call the finalize () method. Objects in this step are not really spam objects. Therefore, the garbage collector has not recycled them from the managed heap.

When the object is ready to be terminated, another Garbage Collector thread will call the finalize () method for each object in the worker queue. After the call is complete, the thread removes the pointer from the worker queue, so that the Garbage Collector knows that the terminated object can be cleared during the next object collection. From the above we can see that a major part of the additional work brought about by the garbage collection mechanism is to call the finalize () method. Therefore, in actual programming, developers should avoid implementing the finalize () method in the class.

Another problem with the finalize () method is that developers do not know when it will be called. Unlike the destructor in C ++, it is called when an object is deleted. To solve this problem, an interface IDisposable is provided in. Net. Microsoft recommends defining objects according to the following pattern when implementing classes with fianlize () methods:

Public class Class1: IDisposable
{
Public Class1 ()
{
}

~ Class1 ()
{
// The Garbage Collector calls this method, so the parameter must be false.
Dispose (false );
}

// This method is defined in the IDisposable interface.
Public void Dispose ()
{
// This method is called by a program. After this method is called, the object is terminated.
// Because we do not want the Garbage Collector to terminate the object again, we need to remove the object from the end list.
GC. SuppressFinalize (this );
// Because the program calls this method, the parameter is true.
Dispose (true );
}

// This method is used to complete all the work related to recycling.
Private void Dispose (bool disposing)
{
Lock (this) // avoid thread errors.
{
If (disposing)
{
// The programmer needs to release the resources occupied by the object.
}

// The object will be terminated by the garbage collector. Add other Code related to object clearing.
}
}
}

Now we understand the basic principles of the garbage collector. Next let's take a look at how the garbage collector works internally. There are many types of garbage collectors. Microsoft implements a Generational Garbage Collector ). The lifetime Garbage Collector divides the memory into many managed heaps, each of which corresponds to a lifetime level. The garbage collector follows the following principles:

The shorter the lifetime of a newly generated object. The longer the object is generated, the longer the lifetime of the object. For the Garbage Collector, it is always faster to recycle some objects than to recycle all objects. Therefore, the garbage collector recycles objects that have a short life cycle more frequently than those that have a long life cycle.

The. Net Garbage Collector currently has three lifetime levels: 0, 1 and 2. The initial size of the managed heap corresponding to levels 0, 1, and 2 is 256 K, 2 M, and 10 M respectively. The garbage collector will change the size of the managed heap if it finds that changing the size can improve the performance. For example, when the application initializes many small objects and these objects are quickly recycled, the garbage collector will change the 0-level managed heap to 128 K and increase the recycling frequency. If the opposite is true, the garbage collector will increase the size of the managed heap when it finds that a large amount of space cannot be recycled in a 0-level managed heap.
Before the application is initialized, all levels of managed stacks are empty. When an object is initialized, it is put into a managed heap with a level of 0 in the initialization sequence. The storage of objects in the managed heap is continuous, which makes the managed heap fast to access objects, because the managed object does not need to search for memory. The garbage collector saves a pointer to the memory space after the last object in the managed heap. Figure 1 shows a zero-level managed heap containing four objects.


Figure 1 hosting heap containing four objects

When the 0-level managed heap is filled with objects, for example, when a program initializes a new object, the size of the 0-level managed heap exceeds 256 kb, the garbage collector checks all objects in the managed heap to check whether any objects can be recycled. When the recycle operation starts, as mentioned above, the garbage collector will find the objects directly or indirectly referenced by the root node and the root node, and then transfer these objects to the level 1 managed heap, move the pointer of the 0-level managed heap to the initial position to clear all objects. Meanwhile, the garbage collector compresses the level 1 managed heap to ensure that there is no memory gap between all objects. When Level 1 hosting is full, the object will be transferred to a Level 2 hosting heap.

For example, in figure 1, the garbage collector starts to recycle objects, assuming that D Objects will be recycled, and the program creates E and F objects. In this case, object 2 in the managed heap is shown.


Figure 2 0-level and 1-level managed heaps after recycling objects

Then the program creates new objects G and H, and triggers the Garbage Collector again. Object E will be recycled. In this case, object 3 in the managed heap is shown.

The principle of the Garbage Collector for survival is also exceptional. When the object size exceeds K, the object will be placed in the "large object area ". Objects in the large object area will not be recycled or compressed by the garbage collector. This is to force the Garbage Collector to only recycle small objects to improve program performance.

Control the Garbage Collector

The. Net Framework provides many methods for developers to directly control the behavior of the garbage collector. By using GC. Collect () or GC. Collect (int GenerationNumber), developers can force the Garbage Collector to recycle managed heaps of all levels. In most cases, developers do not need to interfere with the action of the garbage collector, but in some cases, for example, when the program performs very complex operations and wants to confirm that the garbage objects in the memory have been recycled, you can use the above method. Another method is GC. WaitForPendingFinalizers (). It can suspend the current thread until the thread in the processor queue clears the queue.

The best way to use the garbage collector is to track the objects defined in the program and manually release them when the program does not need them. For example, an object in a program has a string attribute, which occupies a certain amount of memory space. When this attribute is no longer used, developers can set it to null in the program, so that the garbage collector can recycle the space occupied by this string. In addition, if the developer determines that an object is no longer used, the developer must also make sure that no other object references the object. Otherwise, the garbage collector will not recycle the object.

It is also worth mentioning that the finalize () method should be completed in a short period of time, because the Garbage Collector limits a time for the finalize () method, if finalize () if the method has not been completed within the specified time, the garbage collector terminates the thread that runs the finalize () method. In the following cases, the program calls the finalize () method of the object:

The level 0 garbage collector is full.

The program calls the garbage collection method.

The Common Language Runtime is detaching an application domain.

The public Language Runtime is being uninstalled.
(Original address: http://www.yesky.com/20030311/1656401.shtml)

 

Understanding of. Net garbage collection Finalize and Dispose

Let's talk about the Destructor first.

Destructor cannot be inherited. Therefore, apart from the declared destructor, a class does not have any other destructor.

Because destructor must not contain parameters, they cannot be overloaded. Therefore, a class can have at most one destructor.

Destructor are automatically called and cannot be explicitly called. When no code can use an instance, the instance meets the conditions for destruction. After that, the corresponding instance destructor can be called at any time. When an instance is destroyed, each destructor in the inheritance chain of the instance is called in the order from the largest degree of derivation to the smallest degree of derivation. Destructor can be executed on any thread.

Output of the following example

using System;
class A
{
~A() {
Console.WriteLine("A's destructor");
}
}
class B: A
{
~B() {
Console.WriteLine("B's destructor");
}
}
class Test
{
static void Main() {
B b = new B();
b = null;
GC.Collect();
GC.WaitForPendingFinalizers();
}
}

Is

B's destructor
A's destructor

This is because the destructor in the inheritance chain are called in the order from the largest degree of derivation to the smallest degree of derivation.

The Destructor is actually rewritten.System.ObjectVirtual Methods inFinalize. C # This method cannot be rewritten in the program or called directly (or its rewriting ). For example, the following program

class A
{
override protected void Finalize() {} // error
public void F() {
this.Finalize(); // error
}
}

Contains two errors.

The behavior of the compiler is like this Method and Its rewriting does not exist at all. Therefore, the following procedure:

class A
{
void Finalize() {} // permitted
}

Is valid, and the declared method hidesSystem.ObjectOfFinalizeMethod.

Okay. Now let's talk about Finalize and Dispose.

The similarities between Finalize and Dispose (bool disposing) and Dispose () are as follows:

These three services are designed to release unmanaged resource services.

Differences between Finalize and Dispose () and Dispose (bool disposing:

  1. Finalize is a mechanism provided by CLR. It ensures that if a class implements the Finalize method, the garbage collector calls the Finalize method when the class object is reclaimed. developers of this type must release unmanaged Resources in the Finalize method. however, when will Finalize be called is determined by the garbage collector, and the user (customer) of this type of object cannot control it. therefore, it is impossible to release valuable unmanaged resources in a timely manner. because unmanaged resources are more valuable, this will reduce performance.
  2. Dispose (bool disposing) is not a mechanism provided by CRL, but a design pattern (as a method of the IDisposable interface). It aims to make it available to users (customers) of class objects) after using the class object, you can manually call the release of the unmanaged resource in time, without waiting for the time when the class object is reclaimed. developers of such classes only need to port the code originally written in Finalize to the Dispose (bool disposing) to release unmanaged resources. in Finalize, you only need to simply call "Dispose (false)" (Why is false passed.

At this time, we may be confused. Why do we still need a Dispose () method? Is it possible to have only one Dispose (bool disposing) or only one Dispose?
The answer is:
There is only one Dispose (). Why? Because if there is only one Dispose () and there is no Dispose (bool disposing) method. in the code for handling the release of unmanaged resources, you cannot determine whether the method is called by the customer or by the garbage collector through Finalize. it cannot be determined that if it is manually called by the customer, the garbage collector does not want to call Finalize () (call GC. supperFinalize method ). another possible cause (we know that if the garbage collector is called through Finalize, we may reference other managed objects in the release code, at this time, these managed objects may have been garbage collected, which will lead to unpredictable execution results (do not reference other Managed Objects in Finalize ).

Therefore, a bool disposing parameter is required, but if there is only one Dispose (bool disposing), there is a funny requirement for the customer that Dispose (false) has been used by Finalize, the customer must use the Dispose (true) method, but who can ensure that the customer will not use the Dispose (false) method? So here we adopt a design pattern: Reload implements Dispose (bool disposing) as protected, while Dispose () is implemented as Public, so that the customer can only call Dispose () (The Internal call of Dispose (true) // indicates that it is a direct call by the customer), and the customer cannot call Dispose (bool disposing ).

Example:

Public class BaseResource: IDisposable
{
// The Destructor is actually rewritten.System.ObjectVirtual Methods inFinalizeBy default, a class has no destructor, that is, the Finalize method is not called when the object is reclaimed by garbage collection.
~ BaseResource ()
{
// Do not write code that releases unmanaged resources here to ensure code readability and maintainability
// It must be called in the Dispose (false) method, and false indicates that the Dispose (bool disposing) function is called from the garbage collector when the Finalize is called.
Dispose (false );
}


// Cannot be called directly by the customer
// If disposing is true, this method is called directly by the customer, and the hosted and unmanaged resources can be released.
// If disposing is false, the function is called from the garbage collector when calling Finalize. In this case, other hosted objects cannot be referenced. Therefore, only unmanaged resources can be released.
Protected virtual void Dispose (bool disposing)
{

// This method is directly called by the customer, so the hosted and unmanaged resources can be released.
If (disposing)
{
// Release managed resources
OtherManagedObject. Dispose ();
}


// Release unmanaged Resources
DoUnManagedObjectDispose ();


// This method is directly called by the customer, telling the Garbage Collector to clear itself from the Finalization queue to prevent the garbage collector from calling the Finalize method.
If (disposing)
GC. SuppressFinalize (this );

}

// Can be called directly by the customer
Public void Dispose ()
{
// It must be called in the form of Dispose (true). If it is true, the Dispose (bool disposing) function is directly called by the customer.
Dispose (true );
}
}

The purpose of the above example:

1/If the customer does not call Dispose () and fails to release the managed and unmanaged resources in time, there is still a chance to execute Finalize () to release the unmanaged resources during garbage collection, however, this results in a waste of idle resources that are not released in a timely manner.

2/If the customer calls Dispose (), the managed and unmanaged resources can be released in time. When the object is garbage collected, Finalize () is not executed (), improves the efficiency of using unmanaged resources and improves system performance.

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.