可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I asked a question about this method:
// Save an object out to the disk
public static void SerializeObject<T>(this T toSerialize, String filename)
{
XmlSerializer xmlSerializer = new XmlSerializer(toSerialize.GetType());
TextWriter textWriter = new StreamWriter(filename);
xmlSerializer.Serialize(textWriter, toSerialize);
textWriter.Close();
}
in the response I got this as an added remark:
Make sure you always dispose disposable resources such as streams and text readers and writers. This doesn't seem to be the case in your SerializeObject method.
So, I can tell that this is going to seem super lame for someone who has been coding C# for a year or two, but why do I have to dispose it?
Is see that testWriter
has a dispose method, but shouldn't garbage collection take care of that? I came from Delphi to C#. In Delphi I had to clean up everything, so this is not a case of me wanting to be lazy. I just was told that if you force freeing up the memory that your objects take then it can cause bad stuff. I was told to "Just let the garbage collector do it".
- So, why do I need to call dispose? (My guess is that it is because
textWriter
hits the disk.)
- Is there a list of objects I need to be careful with? (Or an easy way to know when I need to call dispose?)
回答1:
You are correct that for properly written code the GC will eventually clean up the native resources. The object will have a finalizer, and during finalization will free up the necessary native resources.
However when this happens is very non-deterministic. Additionally it's a bit backwards because you're using the GC which designed to handle managed memory as a means to manage native resources. This leads to interesting cases and can cause native resources to stay alive much longer than anticipated leading to situations where
- Files are open long after they are no longer used
- Resource handles can run out because the GC doesn't see enough memory pressure to force a collection and hence run finalizers
The using / dispose pattern adds determinism to the cleanup of native resources and removes these problems.
回答2:
The rule of thumb here is pretty simple: always call Dispose()
on objects that implement IDisposable
(not all objects do). You won't always know the reason why an object had to implement Dispose, but you should assume that it is there for a reason.
The easiest way to make sure you do this is through using
:
using (TextWriter tw = new StreamWriter(fileName))
{
// your code here
}
This will call Dispose()
automatically at the end of the using block (it's fundamentally the same as using a try/catch/finally with the Dispose() in the finally block).
For more information on how Dispose works with garbage collection, see here.
回答3:
Garbage collector releases all resources, but the time when it does this is undefined. Dispose method provides a way to release unmanaged resources immediately.
回答4:
If you know you're not going to use a certain resource you can simply dispose of it yourself; you will certainly be faster than the garbage collector and will allow others to use the file or whatever you have opened faster. The easiest way would be to use your TextWriter or any other resource in a using
:
using (TextWriter textWriter = new StreamWriter(filename))
{
xmlSerializer.Serialize(textWriter, toSerialize);
}
This basically ensures the TextWriter is disposed at the end. You don't need it any more than that, anyway.
回答5:
Well actually you already are disposing it since the textWriter.Close Method does it.
public virtual void Close()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
So you could change your code to. This
public static void SerializeObject<T>(this T toSerialize, String filename)
{
TextWriter textWriter;
try
{
XmlSerializer xmlSerializer = new XmlSerializer(toSerialize.GetType());
textWriter = new StreamWriter(filename);
xmlSerializer.Serialize(textWriter, toSerialize);
}
finally
{
textWriter.Close();
}
Which is pretty similar to what the using() does in the other answers.
The impact of not doing this is that if an error occurs with Serialize it would be a while before the Framework gave up its file lock (when it Processes the fReachable queue).
I know FxCop tells you when to implment IDisposable but I don't think there's any easy way to find out when you need to call Dispose other than looking at the Docs and seeing if an object implments IDisposable (or intellisense).
回答6:
If you are using native resources (for example file handles) then you should call Dispose() to close them soon, and not when the GC runs(which might be much later in higher gc generations). And you want to close the file since file access usually locks the file in some way.
回答7:
If you are opening a resource (such as a file, or opening a database connection) then disposing the resource will release its hold on the resource. If you don't do this then other people might not be able to connect to the database or use the file.
As a general rule of thumb....if the class implements the IDisposable interface, then you should call the Dispose() method when you are finishing it. More than likely there was a reason for them making it disposable :)
回答8:
From the TextWriter.Dispose documentation:
Note Always call Dispose before you
release your last reference to the
TextWriter. Otherwise, the resources
it is using will not be freed until
the garbage collector calls the
TextWriter object's Finalize method.
From the Object.Finalize documentation:
The exact time when the finalizer
executes during garbage collection is
undefined. Resources are not
guaranteed to be released at any
specific time, unless calling a Close
method or a Dispose method.
and
The Finalize method might not run to
completion or might not run at all in
the following exceptional
circumstances:
Another finalizer blocks indefinitely
(goes into an infinite loop, tries to
obtain a lock it can never obtain and
so on). Because the runtime attempts
to run finalizers to completion, other
finalizers might not be called if a
finalizer blocks indefinitely.
The process terminates without giving
the runtime a chance to clean up. In
this case, the runtime's first
notification of process termination is
a DLL_PROCESS_DETACH notification.
The runtime continues to Finalize
objects during shutdown only while the
number of finalizable objects
continues to decrease.
回答9:
The garbage collector will indeed "take care of that". Sooner or later. When it gets around to calling the finalizer, after the next garbage collection.
Calling Dispose
ensures that resources (like file handles) get released as soon as possible, thereby making them available for re-use by other processes in the system. Most of the time, you won't notice the difference between calling Dispose
yourself and letting the garbage collector handle it. But there are times when you will. A Web crawler, for example, that creates a lot of HttpWebResponse
objects, will quickly run out of connections if you don't dispose them after use. (Not that I've run into that problem ... no, not me.)
回答10:
The reason to call Dispose rather than waiting for the GC is often because you are using a finite system resource which you want to release as quickly as possible so that other processes or threads can use it. For objects that have the IDisposable pattern, the "using" construct is an easy and readable way to make sure that Dispose is called.
回答11:
In generally you must dispose objects when you do not need them anymore.
Not disposing object when you finish with them will be meaning that will block access to for other processed/applications to them.
回答12:
A programmer thinking that one doesn't have to worry about disposing things because a finalizer will take care of them is like a driver thinking one doesn't have to worry about avoiding collisions because the car has an airbag. Yes, an airbag will make things more survivable, but...