In the comments to an answer I wrote we had a discussion about memory leaks and IDisposable
where we didn\'t come to any real conclusion.
A class that h
If an IDisposable
object has a finalizer that de-allocates unmanaged memory then the memory will be free when the finalizer is called (after it is marked for collection by the GC and placed in the finalizer queue), but if there isn't any finalizer and Dispose()
is never called, then memory can be leaked and only re-claimed when the process terminates.
Failing to call IDisposable on objects which subscribe to events from longer-lived objects will extend the memory-allocation lifetime of the subscriber to be extended to that of the publisher. If there is no upper bound to the number of subscribers that may be attached and abandoned during a publisher's lifetime, this will constitute an unbounded memory leak.
To my knowledge the GC will not call Dispose. You have to call it yourself explicitly or use using. So the answer is: Yes, if the class handles unmanaged resources, which are released in Dispose, your class will leak, if you don't call Dispose.
I will not cause managed memory leaks. It can cause leaks in referenced unmanaged code. But it's worse than that: memory on modern systems is plentiful enough that you can often get by for a while with a bad leak. Witness Mozilla Firefox: it used to (does it still?) leak like a sieve, and millions were happy to use it.
The bigger problem is other resources that may have nothing to do with memory at all. Examples include database connections, system I/O handles, socket handles, file handles, and the like. These are all items where you can easily create denial of service situations on your own system if you aren't careful to use IDisposable properly.
The big issue is when the GC runs.
Take the following class
class GcTest
{
private Stopwatch sw = new Stopwatch();
public GcTest()
{
sw.Start();
}
~GcTest()
{
sw.Stop();
Console.WriteLine("GcTest finalized in " + sw.ElapsedMilliseconds + " ms");
}
}
Put a breakpoint on the Console.WriteLine
if you like.
Create an empty windows forms app, and in the form load event just instantiate a new GcTest
private void Form1_Load(object sender, EventArgs e)
{
var gcTest = new GcTest();
}
Run your application and wait for the finalizer to run.
Most likely it won't run until you close your application.
Just to add a little to Henk and Joel's answers
What you've described happens quite often on DB Connections specifically. Enough that the ADO.NET Performance counter NumberOfReclaimedConnections
got added. This counter tracks...
The number of connections that have been reclaimed through garbage collection where Close or Dispose was not called by the application. Not explicitly closing or disposing connections hurts performance.
The performance hit is usually a longer then necessary wait for a connection to be freed up. This can also result in timeouts on the connection, not a memory problem.