The working principle of GC is described above. Note that GC can only Recycle resources in the managed heap. Other unmanaged resources, such as file resources, buffers, and mutex, cannot be automatically recycled by GC. It must be implemented through the developer's own programming (sometimes it may be difficult to manage CLR resources, because it has some automatic and manual functions, however, compared with C ++, we should be satisfied with the limit _^ ).
A natural encoding method is to write the function that recycles resources into finalize, when GC starts to recycle managed resources, it recycles the unmanaged resources (sometimes I will simply say GC is collected, this means that the code is executed and recycled at GC startup ). However, this may cause many problems. The biggest problem is timing. Developers cannot determine when to start GC (including calling GC. collect () does not work either. This makes it impossible to determine when the unmanaged resources will be released, or determine the order of the resources occupied by different objects.
Therefore, we need to manage unmanaged resources in a mode called dispose. First, let's take a look at the typical dispose mode encoding:
Public class unsafesourceholder: idisposable
{
Private intptr buffer;
Private safehandler resource;
Private bool disposed;
Public unsafesourceholder ()
{
Buffer = ...;
Resource = ...;
Disposed = false;
}
Protected virtual void dispose (bool disposing)
{
If (disposed) return;
Releasebuffer (buffer );
If (disposing)
{
If (resource! = NULL) resource. Dispose ();
}
Disposed = true;
}
~ Unsafesourceholder ()
{
Dispose (false );
}
Public void dispose ()
{
Dispose (true );
GC. suppressfinalize (this );
}
Public void close ()
{
Dispose ();
}
Public void dosomething ()
{
If (disposed) throw new objectdisposedexception ("released resources cannot be used ");
}
}
From the above Code, let's take a look at the key points of the dispose mode. First, if a class (unsafesourceholder in the previous example) contains unmanaged resources (in the previous example, both buffer and resource represent unmanaged resources), it needs to implement the idisposable interface, this interface only has one public void dispose () method. Of course, if you do not implement this interface (for example, put the content in dispose () in close (), there is no problem in theory. However, there are at least two bad points:
1. you have lost a language for talking to the caller. (by default, when the caller sees a class that implements the idisposable interface, the class contains unmanaged resources ), the caller may not know that this class contains unmanaged resources;
2. You have lost some convenient syntax support (for example, the using in C # will automatically help you call the dispose method of this interface ).
Therefore, this is required. Why is there a close () method? There are two reasons:
1. The caller will get used to the name close;
2. CLR uses the dispose () method as an explicit interface method. You must call: (idisposable I). Dispose () in this way, which is troublesome.
Well, when there are managed resources in a class, you need to implement the idisposable interface and expose the above two APIs for the caller to use.
When it comes to calling, let's take a look. There are several ways for a person who calls this type of object to trigger Resource Recycling. One is to explicitly call the dispose or close method (or use the syntax to secretly call it) and notify the user to recycle resources. Another method is to enable GC to automatically Recycle resources. What? I have said that GC cannot recycle unmanaged resources. Well, yes, but I have reloaded the (equivalent to) Finalize () method. What? You didn't see it, so please note ~ Unsafesourceholder. This is not a C ++ destructor. I wrote this function in the above example, which is equivalent to writing the following code:
Protected override void finalize ()
{
Try
{
Dispose ();
}
Finally
{
Base. Finalize ();
}
}
The reason for writing in the method of seemingly destructor is that many developers do not write the code according to the rules, so that the final function throws an exception, causing the process to go down or resource leakage. Therefore, please write in this way that makes many c ++ programmers feel uncomfortable (I personally think this design is a bit superfluous, A developer who does not write such code as try-finally, how are you sure it will write code like destructor ??).
However, we can find out the code carefully. The two call methods are different. Actually, the dispose (bool disposing) function is used to process unmanaged resources. The dispose () method calls dispose (true ), GC calls dispose (false ). What is the difference? To clarify this problem, we need to divide the unmanaged resources into two categories (these are my own statements, and there may be bugs ), the first type is the unmanaged resources enjoyed by only one object, which is expressed in buffer in the preceding example. Another type is the unmanaged resources enjoyed by many objects, which are represented by resouce in the preceding example. The exclusive resource must be released when the object is released, so the resource will be considered to be released during GC calls. However, the other type of shared resources cannot be released by GC, because the GC release order is unstable, and it cannot be confirmed whether other objects are using the resource after the resource is released. Only the caller knows this. Therefore, the caller can only manually call dispose () or close () to release the resource. That is to say, manual calls will release all the unmanaged resources used by the object, and automatic calls can only release the exclusive unmanaged resources of the object.
However, what if the caller encounters an error and uses it again after the unmanaged resource is released? At this time, the object is required to be able to tell the Caller: Are you craze ?. In the above example, the disposed variable is used to record the resource usage status and an objectdisposedexception exception is thrown when it is used illegally (this is also part of the content recommended by the dispose mode ).
In the above Code, there is another GC. suppressfinalize (this); then, the GC is told not to recycle the object automatically. I am not very clear about the reason here. It is said that the object has been explicitly recycled and there is no need to recycle it automatically. I personally think it is wrong, because the explicit recovery is only for unmanaged resources, and the managed resources are not recycled. I checked msdn and some books and thought it would be better to explain that if the garbage collection happens during dispose collection (because the thread is suspended when garbage collection is started, does not affect the collection of unmanaged resources, so the resource will be recycled from two places to generate conflicts), so GC is called. suppressfinalize makes the garbage collection mechanism stop trying to recycle the object for a period of time. Please note that this is a period of time rather than forever.
The above is a basic structure of the dispose mode. The following points are briefly summarized:
1. Implement the idisposable interface.
2. Provides the close () function and calls the dispose () function internally.
3. Implement a dispose (bool disposing) function to process different unmanaged resources.
4. Implement the Destructor (add a pseudo-character to prepare ^_^) so that it can be automatically recycled at GC startup.
5. An objectdisposedexception exception is thrown when a released resource is called (the same resource must be cleared multiple times at the same time ).
6. Use the GC. suppressfinalize function to prevent cleanup conflicts.
Of course, you can further improve its implementation based on the situation (for example, lock the resource during recycling), but its overall idea and basic interface should not be changed. When you implement a class that manages the design of unmanaged resources, follow this mode. However, if you do not have any unmanaged resources in your class, please do not have to wait for something to do. Think about the desired place in the class. ^_^.