SoFunction
Updated on 2025-03-07

C# basics: Detailed explanation of the differences between Dispose, Close, Finalize

.net memory recycling and Dispose, Close, Finalize methods
1. The use of net objects is generally divided into three situations:
1. Create an object
2. Use objects
3. Release the object
2. Create an object
1. Creating an object is actually divided into two steps: variable type declaration and initialization of the object
2. Variable type declaration, such as:

Copy the codeThe code is as follows:

FileStream fs

3. Initialize the object
An object must be initialized before it is used (calling its methods or properties).
like:
Copy the codeThe code is as follows:

fs = new FileStream(@"C:\",);

a. Allocate a piece of memory in the managed heap, and its size is equal to the sum of memory of all fields in FileStream (not including static of course) plus other things that MS thinks are needed.
b. Initialize the field of the object (the value type initializes all bits to 0, the object is initialized to null, of course string is an exception, it is initialized to an empty string)
c. Call the corresponding constructor of FileStream, where a private field of an unmanaged resource (file) will be initialized.
3. Use objects
There is nothing to say about using an object, it is to call the object's methods (or properties, etc.) to complete a certain function. Of course, the scope of the methods called to release the object should not belong to this category (finalize, etc. mentioned now).
4. Release the object
1. Release the object, that is, I no longer need this object. Now I want to release it so that the memory space it occupies on the heap is collected (of course, the memory space of the variable name does not need to be managed, because it will automatically disappear with its scope)
2. .net automatically performs memory management, that is, when it judges that an object is useless (of course it has its own algorithm), it will automatically reclaim its memory, but the time for its recovery is generally uncertain (when .net thinks that memory is tight, it will start)
BTW: Actually, it is impossible for us to just want to reclaim the memory of the object by ourselves, because MS does not provide a way (it is also to start the memory collection function of .net)
Five. The first conclusion
It is very simple to use objects in net. You can just use them directly after creating an object. Don’t worry about it if you don’t use it. The garbage collector will help you get the memory back.
VI. Exceptions
When an object member refers to an unmanaged resource (memory or resources that are not allocated on the hosting heap, such as files, database connections, etc.), the following is an example to illustrate:
Category, this is an unmanaged resource (file) encapsulation object provided by the .net basic class library (its code can be seen by decompiling the Reflector tool)
Undoubtedly encapsulate an unmanaged resource
Looking at its source code, I found that there is such a private member:
Copy the codeThe code is as follows:

private SafeFileHandle _handle;

The Init method called by the constructor can discover the initialization code of this member:
Copy the codeThe code is as follows:

this._handle = (text2, num1, share, secAttrs, mode, num2, 
);

The latter is actually the CreateFile method in it, which returns a HANDLE (i.e., unmanaged resource reference)
2. Let’s use this category first:
Copy the codeThe code is as follows:

using System;
using ;
public class TestFileStream
{
    public static void Main(string[] args)
    {   
//Create a FileStream object
        FileStream fs = new FileStream(@"C:\",);       
("You can try to delete the c drive (Enter key continues) in the system");
//Suspend the program execution and try to delete the file in the system
        ();

//Delete file test
        try
        {
            (@"c:\");
        }
        catch (IOException ex)
        {
("[Error]Program failed to delete file: {0}",);
        }
    }
}


3. When the program is suspended (waiting for input), deleting the file will fail. It is easy to understand. Because the file is not closed after it is opened, the system does not know whether the file is useful, so it helps us protect the file (for sure, the memory used by the unmanaged resource is still occupied by the program)
4. But after the program is executed, we try to delete the file again, and it is successful! Why? (Don't fs not close that SafeFileHandle?)
Of course, you can say that the Windows operating system will automatically recycle its resources after a process is over. That's right (but if it is com, it will be miserable, because com exists in its own process, and the operating system is not responsible for this: (   ), but this is not because of the functions of the Windows operating system, but because of the help of the .net garbage collector.
5. Look at the following example
Copy the codeThe code is as follows:

using System;
using ;
public class TestFileStream
{
    public static void Main(string[] args)
    {
//Create a FileStream object
        FileStream fs = new FileStream(@"C:\", );
("You can try to delete the c drive (Enter key continues) in the system");
//Suspend the program execution and try to delete the file in the system
        ();

/**//*Conduct garbage collection*/
        ();
("Try deleting it again");
        ();
    }
}


6. Pay attention to the middle line of code:
Copy the codeThe code is as follows:

();

This is a forced .net garbage collector to perform garbage collection.
Let's try to delete it again, and it can actually be deleted. Why? (Didn't fs not close the SafeFileHandle?), let me explain in detail:
7. Let’s first understand the four opportunities for garbage collection for .net garbage collector (see: .net framework programming translated by Li Jianzhong)
a. Most common: When .net feels appropriate, for example, it feels memory tight (the devil is called: 0 generation object full)
b. Microsoft strongly does not recommend using: GC Collect method call (this is the one we used above, because it will reduce performance, suspend processes, etc. Anyway, listen to Microsoft. Of course, it can be used at some point, just like the code I used to test above, haha...)
c. When the application domain is uninstalled (AppDomain)
When closed
8. Now we can understand why the file can be deleted after the program is finished, because when the CLR is closed, .net performs garbage collection (that is, the () code equivalent to the second example).
9. So now all the problems are concentrated on garbage collection. What does it do?
a. After the garbage collector judges that an object will not be referenced again, it starts garbage collection (that is, memory recycle)
b. Clear the memory (that is, take back the memory in the managed heap)
c. But what should I do if some fields of the object refer to unmanaged resources? For example, FileStream's _handle
d. So we have to tell the garbage collector that before you recycle my memory, we will first perform a method to retrieve my unmanaged resources, so as not to recycle the memory of the hosted heap by you, and the memory of the unmanaged resources I referenced will be leaked.
e. This method is Finalize(), which is the ~ClassName() method of C# (same as destructive syntax in C++)
f. So if an object has a Finalize method, the garbage collector will automatically call this method before retrieving its memory
g. This way we can clean up those things (unmanaged resources)
From this point of view, the mechanism provided by the garbage collector is to better improve the automatic memory management function of .net, so that we can also participate in garbage collection.
10. Let's take a look at what .Net does when the code () or CLR is closed:
a. The garbage collector started and found that the object referenced by fs was useless (of course, it will be recycled regardless of whether you are useful or not), so it recycles memory.
b. Discover the type of fs: FileStream provides the Finalize method, so this method is called first
(The following continues via Reflector)
There is this._handle.Dispose() code in the method, so () is called
d. Then go to (of course, many circles, please take a little more...) method and find the code: () (i.e. close unmanaged resources--file HANDLE)
It turned out that the garbage collector helped us close the unmanaged resource (of course, it was through the Finalize method we wrote ourselves), so we can delete the file later.
11. Some people may ask: It seems that when we use FileStream objects, it is not so complicated?
Answer: Very Good!
Some people: It's because everyone is as lucky as my example 1. Since the file under the C drive was created, I will never use it any longer, regardless of whether this part of its resources has been leaked or locked. At the end of the program, it was helped by the garbage collector and took back the file HANDLE that I forgot to close.
The remaining part of the people: A "dud" was buried in the program, and they didn't know when it would explode, just like the method in my example showed an abnormality.
(But I think) Most people: After reading a lot of .net programming advice, Microsoft strongly recommends, MSDN standard practices, etc. (and this blog, haha), they know that when using things like FileStream and SqlConnection, they must close them.
With Dispose
The codes for our two examples are not standard. The correct way to do this should be called () after using the FileStream to close it to ensure the security of the resource.
Attachment: The correct way to do it
Copy the codeThe code is as follows:

using System;
using ;
public class TestFileStream
{
    public static void Main(string[] args)
    {
//Create a FileStream object
        FileStream fs = new FileStream(@"C:\", );
/**//*Close after using up FileStream*/
        ();

//Delete file test
        try
        {
            (@"c:\");
        }
        catch (IOException ex)
        {
("[Error]Program failed to delete file: {0}", );
        }
    }
}


13. Someone raised his hand and said so much. I would have to tell me that I had called it.
Brother, the () method is written by you. If you can't call it, your hand is on you. If you don't call it, one day there will be a problem with the program. If you want it, you will call it: Microsoft is really trash, .net is really unstable, or Java is better, safe and reliable... In order to prevent your country from being scolded, MS had to add this to the garbage collection to prevent accidents...
model
Carefully check the basic categories in the .net class library. All categories with Finalize methods basically provide methods such as Dispose, Close, Dispose (bool) and other methods (FileStream is no exception)
15. In fact, no matter whether it is the Dispose, Close, or Finalize methods, the same code should be executed in the end.
the difference:
Finalize method: Only called by Microsoft
Dispose and Close methods: Provides for you to call
Therefore, after you have used those categories, just call Close (without Close, call the Dispose method). Of course, if you forget, don't worry, there is also a garbage collector to help you with the padding.
7. The second conclusion:
1. When you develop a category that encapsulates unmanaged resources (that is, fields in the class refer to unmanaged resources):
A: It is strongly recommended that you provide Finalize method to release unmanaged resources. The .net garbage collector will not help you automatically recycle that part of the resources, but will help you release it by calling your Finalize method. (This guarantees that when the programmer in your category forgets to manually recycle memory, it can also be remedied through the garbage collector)
B. It is strongly recommended that you provide a Close or Dispose method so that programmers using your category can manually release unmanaged resources in your category. (See .net framework programming automatic memory management chapter to implement Dispose mode)
C. If the category encapsulates an object like FileStream (i.e. re-encapsulation of unmanaged resources), a Close or Dispose method should generally be provided unless this member ensures that it is normally closed after each use, that is, transparent to the caller.
2. When you are using a category that encapsulates unmanaged resources:
A: It is strongly recommended that you call the Close or Dispose method provided by it manually release the memory of its unmanaged resources after you know that this category is not useful. There is a saying: There is a loan and a return, it is not difficult to borrow again; if you don’t repay it after borrowing, don’t think about it after borrowing again~~
B: Be careful not to call the relevant methods of the object after manual release, because the object has been damaged.
Again BTW: No matter it is Finalize, Close or Dispose, you cannot explicitly release the hosted heap memory, they will always be Microsoft's "private property" :)
Summarize:Dispose and Close are basically the same. Close is designed for developers who are not familiar with Dispose, and Close makes it easier to understand what it does.
In the .net framework, close() is designed to be public, and the hidden dispose() is called in close(), and then dispose() calls another virtual dispose(bool)
function. So if you inherit from this class, you must implement the dispose(bool) method. The caller will indirectly call the dispose(bool) method you overloaded to release the resource through close().
Because close() is only used to call the hidden dispose() and then call dispose(bool), the user should not change the close behavior.
Classes with the disponse() method implement the IDisposable interface. There are many classes in .net that only provide close(), but not disponse(), but it does implement the idisponse interface.
Why is this?
The reason is because of the implementation mode of the interface --- explicit implementation implicit implementation, the difference between the two: for implicit implementation, you only need to call "new ClassA().Dispose()", but for explicit implementation
For example, dispose() will not be a member function of this classA. The only way to call is to cast the type to IDisposable first, that is, "new ClassA().Dispose()", but ((IDisposable)new ClassA()).Dispose() can be compiled. This meets the design requirements: provide close(), hide dispose(), and implement IDisposeable interface