IDisposable, using and GarbageColleciton

150 views Asked by At

I got stuck in the weeds of how IDisposable and the GarbageCollector work.

Suppose you have an IDisposable object, which doesn't actually have an resources that it's holding onto (but the Dispose() method is going to do something when called). And suppose you declare it in the head of a using block, but don't actually interact with the object over the course of the block.

What guarantees do I have about how GarbageCollection will operate?

i.e.

using(new MyConceptuallyDisposableObject())
{
   DoSomeWork();
   await DoSomeAsyncWork();
}//PointX

Note that:

  • MyConceptuallyDisposableObject doesn't declare a finaliser / destructor.
    • (Assume that developers will never forget to using`.Dispose()` my object)
  • MyConceptuallyDisposableObject doesn't call GC.SuppressFinalise(this) anywhere.

Am I guaranteed that the object that I constructed will:

  1. Will not have .Dispose() called on it before PointX?
  2. Will have .Dispose() called on it at exactly PointX?
  3. Will not get GarbageCollected/Finalised at any point before PointX?
  4. Will not get GarbageCollected/Finalised before it has had .Dispose() called on it?

Suppose I then change my code to make MyConceptuallyDisposableObject call GC.SuppressFinalise(this) in its constructor. (Bearing in mind that there isn't any Destructor or Finaliser)

  1. Does that change any of the answers to the specific questions above?
  2. Does anything change in general, then?
  3. Does it mean that the GC never cleans up my object at all and I'll end up with a memory leak?

*Context:*

Posted for those who are inevitably curious, but PLEASE don't answer based suggesting other ways to achieve this or that I shouldn't do this. Right now, I'm much more invested in understanding the guts of the above concepts in their abstract sense, not discussing whether my initial attempt was sensible.

I want to write a DisposableAction() class, which accepts 2 Actions. One to perform when you construct it, and one to perform when you Dispose() it.

I thought I knew all the answers to the above (and that they were "Yes", "Yes", "Yes", "Yes", "No", "Almost nothing unless you're incredibly perf-sensitive", and "No".), but I've been trying to diagnose a bug which appears to contradict these beliefs.

1

There are 1 answers

3
Enigmativity On

IDisposable and garbage collection are unrelated, except for the one situation where an object implements a finalizer that happens to call .Dispose().

Unless you know for sure, 100%, and explicitly, that an object has a finalizer that calls .Dispose() then you must call .Dispose() explicitly (or with a using) to ensure the object is disposed.

The answers to your questions:

  1. Yes.
  2. Yes.
  3. Yes.
  4. Yes.
  5. No.
  6. No.
  7. No.