Re: FileStream.Close() & GarbageCollection - Memory Leak Question
- From: Lasse Vågsæther Karlsen <lasse@xxxxxxxxxxx>
- Date: Tue, 05 Feb 2008 09:09:18 +0100
Tom wrote:
Thank you Lasse Karlsen!!
I am less concerned about an error being in my code ... but still a
bit confused about understanding the inner workings of
GarbageCollection. I'm looking for a good list of the top 20 or so
most common causes of memory leaks in the C# environment.
There are two, that I can think of, major sources of memory leaks in an application (C# or otherwise).
There's the unintentional, bug-type, memory leak where you simply forget to deallocate memory after you're done with it. This is typically achieved using a non-managed programming language and just forgetting to add the appropriate code, or forgetting to call it. Typical problem is that you return allocated memory out of a function, which the calling code is now responsible for deallocating, but this responsibility is both hard to ensure and hard to communicate.
The other type of memory leak, which is somewhat related, is that you don't explicitly remove references to large data structures when you're done with them. While you don't have to explicitly call code to free memory allocated in a managed world, you still have to make all the information you got about the lifetime for your data available to the garbage collector.
A typical example of this is to have a static variable containing a list of some sorts, and then adding large objects to that list, and then not removing them when you're done with them, keeping the objects around until the program closes.
The "Stream.Close Method" documentation states: "Closes the current
stream and releases any resources (such as sockets and file handles)
associated with the current stream."
I considered the memory a "resource" that would be freed but I have no
supporting evidence for this thought. :( The bridging between managed
and unmanaged components is certainly confusing. In my mind I thought
that if part of the component was unmanaged ... then all of it was?
Now, with your explanation, I am trying to accept that system level
buffers are also "managed" when they are created within the .Net
environment?
Memory is a resource, just not like this in this context.
Dispose/Close typically disposes of "scarce" resources, like handles, files, sockets. Memory is not considered a scarce resource in the same manner.
It is your responsibility to explicitly call dispose/close when you're done with the purpose of the object, file contents, socket communication, etc.
It is the garbage collectors responsibility to remove the memory used by the object when you no longer have any live references to it.
I am use to unmanaged malloc(), free(), fclose() and _fcloseall(). I
guess I should think of the .Net File.OpenRead() as a method that
creates a "partially" managed object?
You should look for the IDisposable interface. If an object implements this interface, it typically uses a scarce resource and you should always dispose of it when you're done with it. In the case of streams, Close does the same as Dispose, and this is also typically true but check the documentation just to make sure.
The IDisposable pattern also lends itself to a very easy to write special syntax in C#:
using (FileStream stream = new FileStream(...))
{
... use the stream here
}
this translates almost directly to:
FileStream stream = new FileStream(...);
try
{
... use the stream here
}
finally
{
stream.Dispose();
}
I wish I could find a comprehensive list of unmanaged resources used
within the .Net environment. My incomplete list only has the two items
mentioned above: 1) Sockets, 2) File handles.
As I said above, you don't need it. Instead, look for IDisposable support, that should be all you need to know.
Off the top of my head I can add a few items though:
- anything related to GUI objects (buttons, windows, static labels, listview, comboboxes, etc.)
- some types of image resources (cursors, icons)
- registry objects (though I'm not 100% positive here)
I've read: (i) In a mixed managed/unmanaged solution you must manually
free unmanaged memory allocations. (ii) Usage of Stream.Close() is
required to "avoid memory leaks". -- But these two statements don't
necessarily suggest the buffer portion in a FileStream object is
either managed or unmanaged.
Stream.Close is not required to avoid memory leaks. It is needed to close the file when you're done with it.
If you don't call Stream.Close, or Dispose, what happens is that once you no longer have any live references to the stream, the object is eligible for garbage collection. You're not, however, guaranteed that this will happen any time soon. In the meantime, the file the stream holds a reference to is open, and thus possibly locked and unavailable to other applications, even your own should you wish to open another stream for it.
However, once the garbage collector collects the object, the stream will be closed correctly.
The only thing IDisposable.Dispose / Stream.Close allows you to do is choose the time you wish to dispose of the unmanaged resources yourself. A properly written class will do it anyway when the garbage collector runs, but this have the consequences that unmanaged resources are held on to and locked for a longer period of time than necessary.
Additionally there are some slight performance considerations when it comes to just letting IDisposable objects lie around until GC picks them up, so the rule is: IDisposable must be disposed of.
I obviously need to read and study a lot more about .Net Memory
Management. Deeper into Yahoo I now go. For now the following *Delphi*
article has my head spinning:
http://dn.codegear.com/article/28344
There are other memory managers for Delphi available that does this as well, the methods are not directly applicable in .NET though. The JCL class libraries comes to mind.
The two types of leaks you need to concern yourself with are:
1. Not explicitly closing streams/sockets (IDisposable) when you're done with the objects, holding the references longer than needed
2. Holding live references to data that you no longer need, which increases the memory usage patterns of your application
You should not have to concern yourself (much) with leaks in the sense of unmanaged resources, unless you start mucking around with P/Invoke. When you do, think "Here there be dragons" and find some good information about it before diving in.
I know zilch about Delphi and am hoping that a similar C# approach is
out there somewhere. The memory dump and tagging in the above article
is very interesting. Excellent tool and article ... just don't force
me into Delphi, please!
I would recommend GUI programming in Python before recommending Delphi nowadays :)
--
Lasse Vågsæther Karlsen
mailto:lasse@xxxxxxxxxxx
http://presentationmode.blogspot.com/
PGP KeyID: 0xBCDEA2E3
.
- Follow-Ups:
- References:
- FileStream.Close() & GarbageCollection - Memory Leak Question
- From: Tom
- Re: FileStream.Close() & GarbageCollection - Memory Leak Question
- From: Lasse Vågsæther Karlsen
- Re: FileStream.Close() & GarbageCollection - Memory Leak Question
- From: Tom
- FileStream.Close() & GarbageCollection - Memory Leak Question
- Prev by Date: Re: .net compact/smartphone
- Next by Date: Re: C# 2.0 download file's status
- Previous by thread: Re: FileStream.Close() & GarbageCollection - Memory Leak Question
- Next by thread: Re: FileStream.Close() & GarbageCollection - Memory Leak Question
- Index(es):
Relevant Pages
|