Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is There a Time at which to ignore IDisposable.Dispose?

Certainly we should call Dispose() on IDisposable objects as soon as we don't need them (which is often merely the scope of a "using" statement). If we don't take that precaution then bad things, from subtle to show-stopping, might happen.

But what about "the last moment" before process termination? If your IDisposables have not been explicitly disposed by that point in time, isn't it true that it no longer matters? I ask because unmanaged resources, beneath the CLR, are represented by kernel objects - and the win32 process termination will free all unmanaged resources / kernel objects anyway. Said differently, no resources will remain "leaked" after the process terminates (regardless if Dispose() was called on lingering IDisposables).

Can anyone think of a case where process termination would still leave a leaked resource, simply because Dispose() was not explicitly called on one or more IDisposables?

Please do not misunderstand this question: I am not trying to justify ignoring IDisposables. The question is just technical-theoretical.

EDIT: And what about mono running on Linux? Is process termination there just as "reliable" at cleaning up unmanaged "leaks?"

LATE EDIT: Although "other uses" may exist for IDisposables, my focus is strictly on resource leaks. I've heard two answers: (1) if your process refuses to terminate, you will have a leak and (2) yes, resources can leak even if the process terminates. I certainly agree with item (1), though it is just outside the scope of what I'm after. Otherwise, item (2) is exactly what i'm looking for, but I can't shake the feeling it is just a guess. Jeffrey Richter ("Windows via C/C++") explains that a (gracefully) terminated Win32 process will not leave leaked or orphaned resources. Why would a process containing the CLR change that? Where is the documentation, specific example, or theoretical scenario that gives credance to the idea that the Win32 process cleanup capability is compromised when using the CLR?

like image 993
Brent Arias Avatar asked Apr 27 '10 02:04

Brent Arias


2 Answers

Technically speaking, it all depends on what the IDisposable does. It has been used for a lot of things, not just unmanaged resources.

For example, when working on an Outlook application I had built a nice little abstraction of the Outlook API. Attachments were particularly annoying to work with as streams because you needed to save it out to a temp file, work with it, then clean it up.

So my abstraction looked something like this:

OutlookMailItem mailItem = blah;
using (Stream attachmentStream = mailItem.OpenAttachment("something.txt")) {
   // work with stream
}

When Dispose was called on the AttachmentStream, the temp file it was based on was deleted. In this case, if Dispose was not called, the temp file would never be cleaned up. I had a process at startup to look for these orphaned files but I figured I'd present this as an example.

In reality, nearly all IDisposable implementations which wrap some kind of socket, handle, or transaction will simply be cleaned up by the operating system upon process termination. But obviously that's like welfare. Avoid it if you can.

like image 103
Josh Avatar answered Nov 06 '22 01:11

Josh


During a cooperative shutdown, the AppDomain is unloaded, which causes all finalizers to execute:

From Object.Finalize documentation:

During shutdown of an application domain, Finalize is automatically called on objects that are not exempt from finalization, even those that are still accessible.

So you're safe on shutdown as long as two criteria are met:

  • Every IDisposable object that's still alive has a correctly-implemented finalizer (true of Framework classes, may not be true of less-trustworthy libraries); and

  • It's actually a cooperative shutdown, and not an abnormal shutdown such as a hard process termination, Ctrl-C in a console app, or Environment.FailFast.

If either of these two criteria aren't met, it is possible that your application is holding onto global unmanaged resources (such as a mutex), which actually will leak. Therefore, it's always better to call Dispose early if you can. Most of the time, you can rely on the CLR and object finalizers to do this work for you, but better to be safe than sorry.

like image 44
Aaronaught Avatar answered Nov 06 '22 01:11

Aaronaught