C # Release of unmanaged resources (finalize & dispose) Method

Source: Internet
Author: User

From: http://www.cnblogs.com/lzhdim/archive/2009/11/04/1595845.html


Before learning about finalize and dispose, we need to understand two concepts: managed resources and non-commissioned resources.
A. managed resources generally refer to the memory resources controlled by CLR. The management of these resources can be controlled by CLR, such as objects allocated in the program and variables in the scope.
B. Non-managed resources are components that the CLR cannot control or manage. There are many such resources, such as file streams, database connections, system Window handles, and printer resources ...... These resources generally do not exist in heap (where the memory is used to store object instances.
. In the. NET platform, CLR provides a good memory management mechanism for programmers, so that programmers do not need to explicitly release their own memory resources when writing code (these must be explicitly released by the programmers themselves in the previous C and C ++ ). This management mechanism is called GC (garbage collection ). GC plays an obvious role. When the system memory resources are scarce, it will be stimulated, then, it automatically releases the unused managed resources (that is, the programmer does not explicitly release the objects ).
As mentioned above, the GC function of CLR can only release managed resources. For unmanaged resources such as Windows, files, and network connections, it can only track the lifetime of unmanaged resources, I don't know how to release it. In this way, when the resources are used up, the services that the resources can provide will become unavailable, and the running speed of Windows will become slower. This will happen in the connection of the database. If you do not explicitly release a database resource, if you continue to apply for database resources, then, the program will throw an exception.
Therefore, when we encapsulate operations on unmanaged Resources in the class, we need to explicitly or implicitly release these resources. The finalize and dispose methods mentioned above are the methods used in implicit and explicit Operations respectively.
In general, finalize is used for classes whose base classes do not contain the close method or the explicit dispose method. That is to say, in the finalize process, we need to implicitly release unmanaged resources, then, the system releases the managed resources after the finalize process is complete.
To implement the dispose method, you can implement the idisposable interface so that you can execute the dispose method and release resources while using this class.

The following describes how to use the Finalize and dispose methods proposed on msdn. If your class complies with this standard, the class you write will be a "Good Citizen" on the. NET platform ".

The following rules summarize the instructions for using the Finalize method.

1. Implement finalize only on the object to be terminated. Performance overhead related to the Finalize method exists.
If you need the Finalize method, you should consider implementing idisposable so that the class users can avoid the overhead caused by calling the Finalize method. (Juky_huang note: In the class implementing idisposable, you can use GC. suppressfinalize to stop the finalize operation. In this way, as long as the dispose method is explicitly called, you can get a lower overhead. If you do not explicitly call the dispose method, that is, you have not stopped the finalize operation. In this way, you can implicitly release unmanaged resources)
2. Do not make the Finalize method more visible. It should be protected, not public. (Juky_huang Note: This is very important. The Finalize method is generally a system call, and the user does not explicitly call it)
[Page] 3. The Finalize method of the object should release any external resources owned by the object. In addition, the Finalize method should only release resources controlled by objects. The Finalize method should not reference any other objects.
4. Do not directly call the Finalize method for objects that are not the object's base class. In C # programming language, this is not a valid operation.
5. Call the base. Finalize method from the Finalize method of the object. (Juky_huang Note: The Finalize method of the base class called by the derived class)
Note that the Finalize method of the base class is automatically called by the Destructor syntax of the managed extension of C # And C ++.

The following rules summarize the Usage Guide of the dispose method:

1. Implement a disposal design scheme on the type of resources to be released in encapsulation. You can call the public dispose method to release external resources.
2. Implement a disposal design scheme on the base types that generally contain derived types that control resources, even if the base types are not required. If the base type has the close method, this usually indicates the implementation of dispose. In this case, do not implement the Finalize method on the base type. Finalize should be implemented in any derivative type that introduces the resources to be cleared.
3. Use the dispose method of the type to release any disposal resources owned by the type.
4. Disable the Finalize method from running by calling the GC. suppressfinalize method after dispose is called for the instance. The exception to this rule is that it is rare to use finalize to complete the work that dispose does not cover.
5. If the base class implements idisposable, call the dispose method of the base class.
6. Do not assume that dispose will be called. If dispose is not called, use the Finalize method to release the unmanaged resources of the type.
7. After the resource is disposed, an objectdisposedexception is triggered from the instance method on this type (not dispose. This rule is not applicable to the dispose method, because the method can be called multiple times without exception.
8. The call is propagated to dispose through the hierarchy of the base type. The dispose method should release all resources controlled by this object and any objects owned by this object. For example, you can create an object similar to textreader to control stream and encoding, both of which are created by textreader without the user's knowledge. In addition, both stream and encoding can obtain external resources. When the dispose method is called for textreader, it should call dispose for stream and encoding in sequence to release their external resources.
9. It should be considered that the object cannot be used after the dispose method of the object is called. It is difficult to recreate the disposed objects.
10. Allow the dispose method to be called multiple times without exception. This method should do nothing after the first call.

With the above foundation, let's look at a piece of code, which is an implementation of dispose. This code is very interesting if you carefully consider it, here we will see a very common technology in C #, polymorphism. If you have read an article I wrote earlier about virtual methods, you can understand the essentials of the following code.

Public class baseresource: idisposable
// Pointer to an external unmanaged resource. [Page]
// Unmanaged Resources
Private intptr handle;
// Other managed resource this class uses.
// Host resources
Private component components;
// Track whether dispose has been called.
// Indicates whether the resource has been released
Private bool disposed = false;

// Constructor for the baseresource object.
Public baseresource ()
// Insert appropriate constructor code here.

// Implement idisposable.
// Do not make this method virtual.
// A derived class shocould not be able to override this method.
// Display the call method to external users. The actual operation is implemented in the class's parameter-based virtual function dispose (bool disposing ).
Public void dispose ()
// Indicates that the user displays the call
Dispose (true );
// Take yourself off the Finalization queue
// To prevent finalization code for this object
// From executing a second time.
// Because the user displays the call, the resource release is not completed by GC.
GC. suppressfinalize (this );

// Dispose (bool disposing) executes in two distinct scenarios.
// If disposing equals true, the method has been called directly
// Or indirectly by a user/'s code. managed and unmanaged Resources
// Can be disposed.
// If disposing equals false, the method has been called by
// Runtime from inside the finalizer and you shoshould not reference
// Other objects. Only unmanaged resources can be disposed.
Protected virtual void dispose (bool disposing)
// Check to see if dispose has already been called.
// If the instance has been released and no operation is performed again, the instance is called multiple times.
If (! This. disposed)
// If disposing equals true, dispose all managed
// And unmanaged resources.
If (disposing)
// Dispose managed resources.
// If the user displays the call, We need to manually operate the managed resource.
Components. Dispose ();
// Release unmanaged resources. If disposing is false,
// Only the following code is executed.
Closehandle (handle );
Handle = intptr. zero;
// Note that this is not thread safe.
// Another thread cocould start disposing the object
// After the managed resources are disposed,
// But before the disposed flag is set to true.
// If thread safety is necessary, it must be [Page]
// Implemented by the client.

Disposed = true;

// Use C # destructor syntax for finalization code.
// This destructor will run only if the dispose method
// Does not get called.
// It gives your base class the opportunity to finalize.
// Do not provide Destructors in types derived from this class.
// Destructor
~ Baseresource ()
// Do not re-create dispose clean-up code here.
// Calling dispose (false) is optimal in terms
// Readability and maintainability.
// Indicates that this call is an implicit call, called by the Finalize method, that is, the managed resource is released by GC.
Dispose (false );

// Allow your dispose method to be called multiple times,
// But throw an exception if the object has been disposed.
// Whenever you do something with this class,
// Check to see if it has been disposed.
Public void dosomething ()
If (this. disposed)
Throw new objectdisposedexception ();

// Design pattern for a derived class.
// Note that this derived class inherently implements
// Idisposable interface because it is implemented in the base class.
Public class myresourcewrapper: baseresource
// A managed resource that you add in this derived class.
Private managedresource addedmanaged;
// A native unmanaged resource that you add in this derived class.
Private nativeresource addednative;
Private bool disposed = false;

// Constructor for this object.
Public myresourcewrapper ()
// Insert appropriate constructor code here.
// Override the dispose method, release the resources of the derived class, and call the dispose method of the base class.
Protected override void dispose (bool disposing)
If (! This. disposed)
If (disposing)
// Release the managed resources you added in
// This derived class here.
Addedmanaged. Dispose ();
// Release the native unmanaged resources you added
// In this derived class here.
Closehandle (addednative );
This. Disposed = true; [Page]
// Call dispose on your base class.
Base. Dispose (disposing );
// Here, the derived class is not implemented ~ The myresourcewrapper and public dispose methods should have inherited these features of the base class. This is what I said is the essence of the Code in this example. He used the polymorphism principle and I will analyze it briefly below.
// This derived class does not have a Finalize method
// Or a dispose method without parameters because it inherits
// Them from the base class.

In this example, there are two classes: baseresource and myresourcewrapper. First, we must understand the following points:
1. the type of dispose method should release all its resources. It should also call the dispose method of its parent type to release all resources of its base type. The Parent-type dispose method should release all its resources and also call its parent-type dispose method to spread the mode throughout the base-type hierarchy.
2. If the dispose method is explicitly called, we can release managed and unmanaged Resources in the dispose method, and use the GC. suppressfinalize method to stop the Finalize method. If you call the dispose method, you do not need to release the resource implicitly. finalizes will greatly degrade the performance. (Finalize is generally used only when the user does not explicitly call the dispose method. It is used only when it is implicitly completed)
3. Ensure that resources are always correctly cleared. The dispose method should be called multiple times without any exception.

The most important method in this example is the parameter-based dispose method. All the specific operations in this example are implemented here. It is a protected virtual function and can be overwritten by a derived class, in addition, if the derived class has its own call to the unmanaged resources, the derived class should first release its own resources and then call the base according to the requirements mentioned above. dispose to release the base class resources. (Juky_huang Note: This is what we call the propagation feature)
The parameter-based dispose method uses the parameter disposing to determine whether the dispose operation was initiated by finalize or by explicitly calling the public dispose method. If this parameter is set to true, the request is initiated by the public dispose method. If this parameter is set to false, the request is initiated when the GC calls the Finalize method. If this parameter is set to true, you need to release the managed and unmanaged resources and disable the finalize operation of GC, because you can directly call the display to reduce the performance overhead. If it is false, it means that we only need to release the unmanaged resources, because this call is caused by the Finalize of GC, so the release of managed resources can be completed by GC.
Note that when dispose is called multiple times, if the resource has been disposed of, we need to ignore this operation without throwing an exception. This feature is determined by disposed. Now let's take a look at the essence of this program, that is, in the derived class, there is no public dispose method, and the Finalize method (that is, the destructor ), so how can we release resources when we call a derived class object? At first, I didn't know much about it. Later, I took a closer look and suddenly found that it was actually very simple, it uses the polymorphism of the class to complete.
Because method rewriting is used in the derived class, the maximum degree of derivation of the dispose (bool disposing) method in the derived class is. Because the Finalize and public dispose methods [Page] in the base class call the dispose (bool disposing) method, the final call is the function with the highest degree of derivation, in other words, the Finalize and public dispose methods in the derived classes call their own dispose (bool disposing) methods.

For example, now we have a derived class instance. the dispose () method is used to call the public dispose method in the Foundation. This is because of inheritance. In the public dispose method, the dispose (bool disposing) method is called, since this method has been rewritten, it does not actually call the dispose (bool disposing) method in the base class, but a's own dispose (bool disposing) method. This is determined based on the runtime type. So we finally implemented it. We first call the resource release method in A and then call the base. dispose method to release the base class resources.
If the user does not display the call to the dispose method, the Finalize method will be effective, and the process is similar to the above.

From the above we can see that there is a good rule for the release of unmanaged resources. As long as we follow this rule, the code you write is "good people" in. net ".

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.