In a. NET programming environment, the system's resources are divided into managed and unmanaged resources.
The recycling of managed resources does not require manual intervention, and you cannot interfere with their recycling, all you can do is understand how the . NET CLR does these things. This means that for most objects created by your application, you can rely on the garbage collector of the . NET Framework to perform all the necessary memory management tasks implicitly.
The resources are divided into two kinds, managed memory resources, this is not need us to worry about, the system has been managed for us; then for unmanaged resources, here again, is the Stream, database connection, GDI + related objects, as well as COM objects and so on these resources, We need to release it manually.
For unmanaged resources, after you have used these unmanaged resources in your application, you must display the release of them, such as a file object for System.IO.StreamReader, the Close () method of the calling object that must be displayed, or it will consume the system's memory and resources. And there may be an unexpected error.
I would like to say here that it is important to understand what a managed resource is and what is a non-managed resource. Release.
The most common type of unmanaged resource is the object that wraps an operating system resource , such as a file, a window, or a network connection , although the garbage collector can track the lifetime of objects that encapsulate unmanaged resources. However, it does not understand how to clean up these resources specifically. It's okay . The net Framework provides a finalize () method that allows for the appropriate cleanup of unmanaged resources when the garbage collector reclaims that class of resources. If you search for Finalize in the MSDN Library, you will find many similar topics, listing several common unmanaged resources:
Applicationcontext,brush,component,componentdesigner,container,context,cursor,filestream,font,icon,image, Matrix,object,odbcdatareader,oledbdatareader,pen,regex,socket,streamwriter,timer,tooltip
And so on resources. It may not be noticed in the use of a lot of time.
About managed resources, such as simple int,string,float,datetime and so on, more than 80% of the resources in. NET are managed resources.
How unmanaged resources are freed, the. NET Framework provides a object.finalize method that allows an object to properly clean up its unmanaged resources when the garbage collector reclaims the memory used by the object. By default, the Finalize method does not perform any action. By default, the Finalize method does not perform any action. If you want the garbage collector to perform cleanup operations on an object before it reclaims the object's memory, you must override the Finalize method in the class. However, it can be found that in real programming it is impossible to override method Finalize (), in C #, the Finalize method and the call to the base class's Finalize method can be generated automatically through destructors.
For example:
~myclass ()
{
//perform some cleanup operations here.
}
The code is implicitly translated into the following code.
protected override void Finalize ()
{
try
{
//perform some cleanup operations here.
finally
{
base. Finalize ();
}
}
However, in programming, the override method is not recommended for Finalize (), because implementing a Finalize method or destructor can have a negative impact on performance. For a simple reason: the memory used by the Finalize method to reclaim the object requires at least two garbage collection, and when the garbage collector reclaims it, it reclaims the inaccessible memory without the finalizer (Finalize method), and he cannot recycle the Terminator (Finalize method) Memory that cannot be accessed. Instead, it removes the items from the terminating queue and places them in the list of objects marked "ready to terminate". The items in the list point to the object in the managed heap that is ready to be called its termination code, which is reclaimed and freed the next time the garbage collector reclaims it. C # Managed and unmanaged object management
The objects in C # are classified as value types and reference types, and the biggest difference is in how data is stored and where it is stored. The Windows operating system uses a virtual addressing system to manage the storage of data that is generated when the program is running. To put it simply, the system manages an area of memory in which a portion of it is allocated to store value-type variables, called stacks, and the stack uses the advanced principle Stores the value type variable from the highest address bit of the zone to the low address. Advanced out, the LIFO management way to ensure that the value type variables in the scope of the domain can be even after the removal of memory area, due to the fast stack, the data saved generally not too large, this part generally does not require user specialized operations. Value types are saved in a stack rollup, and the stack has very high performance, but is still less flexible for all variables. Usually we want to use a method to allocate memory to store some data, and the data is still available for a long time after the method exits. This possibility exists whenever a storage space is requested with the new operator-for example, all reference types. The managed heap will be used at this point. It works under the control of the garbage collector, and the managed heap (or heap) is another memory area in the large memory area administered by the system. To understand how the heap works and how to allocate memory for reference data types, look at the following code:
Customer Arabel = new Customer ();
This line of code completes the following operations: First, allocate the memory on the heap to store the customer instance (a real instance, not just an address). The value of the variable Arabel is then set to the memory address assigned to the new Customer object (it also invokes the appropriate customer () constructor to initialize the fields in the class instance, but we do not have to worry about this part).
The customer instance is not placed on the stack, but is placed in the memory heap. If we do this:
Customer newaddress = Arabel;
At this point, newaddress is also saved on the stack with the same value as Arabel, which is the heap address where the customer instance is stored.
Knowing this, we'll find a problem with the Arabel and newaddress two variables in the stack that are destroyed, and what the customer object is saved in the heap. In fact, it remains in the heap until the program stops, or the garbage collector deletes it. If a call is not displayed, the C # garbage collector runs and checks the memory periodically, deleting data that is not referenced by any variables. It seems to be good, but think about it, the garbage collector does not always check, it is timed to run, and during this time if a large number of expired data resides in memory .... Then maybe we can force the garbage collector to run somewhere in the code by calling System.GC.Collect (), System.GC is a. NET base class that represents the garbage collector, and the Collect () method invokes the garbage collector. However, there are few occasions where this approach is applicable, (is it the destruction of an object that allows garbage collection to check memory?) For example, a large number of objects in your code that just stop referencing are appropriate for calling the garbage collector. Moreover, the logic of the garbage collector does not guarantee that all expired data will be removed from the heap during a garbage collection, and that it is powerless for unmanaged objects (such as file handles, network connections, and database connections ) that are not managed by the garbage collector. How do you do that?
A special rule is needed to ensure that unmanaged resources are freed when an instance of the class is reclaimed.
When defining a class, you can use two mechanisms to automatically dispose of unmanaged resources. These mechanisms are often implemented together, as each mechanism provides a slightly different solution to the problem. These two mechanisms are:
Declares a destructor, as a member of a class
Implementing the System.IDisposable interface in a class
These two mechanisms are discussed in turn, and then how to implement them at the same time to get the best results. destructor
It is described earlier that constructors can specify certain actions that must be made when an instance of a class is created, or destructors can be called when the garbage collector deletes an object. Because of this, the destructor at first appears to be the best place to put code that frees unmanaged resources and performs general cleanup operations. But things are not so simple. Because the rules of the garbage-back run determine that code that needs to run at a certain time cannot be placed in the destructor, if the object occupies valuable and important resources, the resource should be freed as quickly as possible, and the garbage collector cannot wait to release it. IDisposable Interface
One way to recommend alternative destructors is to use the System.IDisposable interface. The IDisposable interface defines a schema (with language-level support), provides a mechanism for freeing unmanaged resources, and avoids the inherent problem with garbage-related functions that destructors inherently have. The IDisposable interface declares a method Dispose (), which takes no arguments and returns the execution code for the Void,myclass method Dispose () as follows:
Class myclass:idisposable
{public
void Dispose ()
{
//Implementation
}}
}
The execution code for Dispose () explicitly releases all unmanaged resources that are used directly by the object and invokes Dispose () on all encapsulated objects that implement the IDisposable interface. In this way, the Dispose () method provides precise control when releasing unmanaged resources.
Suppose there is a class resourcegobbler that uses some external resources and executes the IDisposable interface. If you want to instantiate an instance of this class, use it, and then release it, you can use the following code:
Resourcegobbler theinstance = new Resourcegobbler ();
This is the Theinstance object's use Process
theinstance.dispose ();
If an exception occurs during processing, the code does not release resources used by theinstance, so you should use a try block to write the following code:
Resourcegobbler theinstance = null;
Try
{
theinstance = new Resourcegobbler (); This is the Theinstance object's use process
}
finally
{
if (theinstance!= null) theinstance.dispose ();
}
Even if an exception occurs during processing, this version ensures that Dispose () is always raised on theinstance and always releases the resources used by theinstance. However, if you always repeat such a structure, the code can easily be confused. C # provides a syntax to ensure that Dispose () is automatically invoked on an object when the reference is out of scope (but not close ()). The syntax uses the Using keyword to do this-but currently, in a completely different environment, it has nothing to do with namespaces. The following code generates the IL code corresponding to the try block:
using (Resourcegobbler theinstance = new Resourcegobbler ())
{
// This is the use procedure for Theinstance objects
}
The using statement is followed by a pair of parentheses, which is the declaration and instantiation of the reference variable, which causes the variable to be placed in the accompanying compound statement. Also, when a variable goes out of scope, its Dispose () method is automatically invoked even if an exception occurs. If you have used a try block to catch other exceptions, it is clearer that you can avoid additional indentation if you avoid using a using statement and call Dispose () only in the finally clause of an existing try block.
Attention:
For some classes, using close () is more logical than Dispose (), for example, when working with files or database connections. In these cases, the IDisposable interface is often implemented, and a separate close () method is executed to invoke Dispose (). This method is clear on the use of the class and also supports the using statement provided by C #.
The preceding sections discuss two ways that the class uses to release unmanaged resources:
The runtime enforces a destructor, but the execution of the destructor is indeterminate and, because of the way the garbage collector works, it adds an unacceptable overhead to the runtime.
The IDisposable interface provides a mechanism to allow users of a class to control the time it takes to dispose of resources, but to ensure that Dispose () is performed.
In general, the best approach is to implement both mechanisms to gain the advantages of both mechanisms and overcome their shortcomings. Suppose most programmers can call Dispose () correctly, implement the IDisposable interface, and use the destructor as a security mechanism to prevent the call to Dispose (). Here is an example of a double implementation:
public class Resourceholder:idisposable {private bool isdispose = false;
Pointer to an external unmanaged resource private INTPTR handle;
Use of other managed resource//shows the called Dispose method public void Dispose () {Dispose (true); Gc.
SuppressFinalize (this);
}//The actual purge method protected virtual void Dispose (bool disposing) {if (!isdisposed) {
if (disposing) {///Here the operation to clear the managed object is performed.
///Here performs the operation to clear the unmanaged object CloseHandle (handle);
handle = IntPtr.Zero;
} isdisposed=true;
}//destructor ~resourceholder () {Dispose (false); }
}
As you can see, Dispose () has a second protected overload method with a bool parameter, which is really the way to do the cleanup work. Dispose (BOOL) is invoked by destructors and IDisposable.Dispose (). The point of this approach is to make sure that all the cleanup code is in one place.
The parameter passed to dispose (bool) indicates whether Dispose (bool) is called by a destructor or IDisposable.Dispose ()--dispose (BOOL) is not called from elsewhere in the code, because:
If the customer invokes IDisposable.Dispose (), the customer specifies that all resources associated with the object, including managed and unmanaged resources, should be cleaned up.
If a destructor is invoked, in principle, all resources still need to be cleaned up. In this case, however, the destructor must be called by the garbage collector and should not access other managed objects because we are no longer able to determine their state. In this case, it is best to clean up the known unmanaged resources, and you want to reference the managed object as well as destructors to perform your own cleanup process.
The Isdispose member variable indicates whether the object has been deleted and allows you to ensure that member variables are not deleted more than once. This simple method is not thread-safe and requires the caller to ensure that only one thread calls the method at the same time. Requiring the customer to synchronize is a reasonable assumption throughout. NET class libraries, such as in the collection class, are used repeatedly. Finally, IDisposable.Dispose () contains a pair of System.GC. Call to the SuppressFinalize () method. The SuppressFinalize () method tells the garbage collector that a class no longer needs to invoke its destructor. Because Dispose () has done all the cleanup required, the destructor does not need to do any work. Calling SuppressFinalize () means that the garbage collector does not think the object has a destructor at all.
Correct understanding of the above content, you can greatly optimize the system performance, timely release of unwanted data, can not rely on C # to provide automatic recycling mechanism, but also require programmers to use a more flexible approach. The combination of both makes the program run fast and make the system more stable.