Question on implementing IDisposable

P

phl

hi,

My question is:

1. To avoid possible memory leaks, when you use this pattern, after you
have dealth with the unmanaged resources and before you take your
object off the finalize queue, how are you sure that your managed
object resources are completely freed up of resources it's might be
using? In my case below I have a private bool variable. Are there any
other managed resource that you might need to explicitly free up in
Dispose?

2. I have the example in msdn that instanciates a Component object but
doesn't actually do anything with it, what is this class for?

Thanks
-phl

Here's some pseudo code:


public classA : IDisposable
{
private Component component = new Component(); //WHAT IS THIS
FOR????
private XmlTextReader reader;
private bool disposed = false;


public LoadFile(string FilePath)
{
reader = new XmlTextReader(FilePath);
}


public void CloseFile()
{
reader.Close();
}

public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}


public void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
CloseFile();
//are there anything else you need to free up
here?????
}
}

this.disposed = true;
}

ClassA()
{
Dispose(false);
}
}
 
B

Barry Kelly

You seem to be confusing two distinct but related topics:

1) Implementing IDisposable so that classes which use other objects as
part of their implementation, which themselves need disposing, can be
disposed of, in a recursive manner.

2) Implementing .NET finalizers, for freeing unmanaged resources, which
also involves implementing IDisposable.
1. To avoid possible memory leaks,

The IDisposable pattern is for resource leaks, typically not memory
leaks.
when you use this pattern, after you
have dealth with the unmanaged resources and before you take your
object off the finalize queue

Now you are talking about finalization - which is something different
from simply implementing IDisposable. Many objects implement IDisposable
to permit closing of files etc. - i.e. deterministic deallocation of
resources used by the class.

That is something *different* from Finalize() (aka ~MyClassName()),
which is for unmanaged resources *directly* represented by the managed
class.

You should only need to implement a finalizer (i.e. ~MyClassname()) when
you are wrapping an OS resource.
how are you sure that your managed
object resources are completely freed up of resources it's might be
using?

I don't understand this question, sorry.
2. I have the example in msdn that instanciates a Component object but
doesn't actually do anything with it, what is this class for?

What example, where? I presume it is a *placeholder* for something which
implements IDisposable (Component itself implements IDisposable), such
as a Stream or other resource.
public classA : IDisposable
{
private Component component = new Component(); //WHAT IS THIS
FOR????

I presume it is a placeholder.
private XmlTextReader reader;
private bool disposed = false;

This protects the class from being disposed multiple times. This is to
permit calling Dispose() multiple times - this is not an error.
public LoadFile(string FilePath)
{
reader = new XmlTextReader(FilePath);
}

public void CloseFile()
{
reader.Close();
}

I don't understand this code, this will throw an exception if LoadFile()
was never called.
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);

This class does not implement a finalizer (i.e. there is no ~classA()
method), so it does not need to call GC.SupressFinalize().
}

public void Dispose(bool disposing)

The overloaded Dispose which takes a bool argument should be made
virtual and protected. The reason behind this pattern is to centralize
logic for classes that need finalizers (which this class doesn't,
because it only contains other managed resources).

The idea behind this pattern is based on classes that implement a
finalizer, and that thus there are two ways that the Dispose method can
get called:

1) Explicitly via IDisposable.Dispose().

2) From the finalizer of this class.

When the method is called via IDisposable.Dispose(), then it needs to
dispose objects it references, as well as its own unmanaged resources.

When the method is called via the finalizer, it shouldn't access objects
it references, since they are dead objects - finalization only occurs
for objects no longer reachable from the main application object graph.

That's why the implementation of this method has the pattern:

---8<---
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// dispose referenced, managed resources
}
// dispose unmanaged, native OS resources
}
--->8---

For future proofness, this pattern is sometimes also used for classes
which don't have a finalizer. The reason this is done is that the class
may have descendants which also need some disposal logic. The idea is
that the descendants can override this protected Dispose method and
perform their disposal of managed resources, before calling the base
class's Dispose(bool). Then, the base class can implement IDispose, so
the subclasses don't (and shouldn't) need to.

Basically, with respect to IDisposable, there are three kinds of
classes:

1) Classes which don't need disposing.

2) Classes which use (i.e. have "ownership" semantics on a private
reference to) objects which need disposing, and therefore need disposing
themselves.

3) Classes which need finalizers, and therefore need disposing for
deterministic cleanup. These classes deal with unmanaged resources, and
thus are extremely rare.

Objects in category 1 don't need to implement IDisposable.

Objects in category 2 and 3 do need to implement IDisposable.

For objects in category 2, the dispose pattern is for future-proofness
and to permit descendants to be disposed when the IDisposable.Dispose()
method is called via the base class.

For objects in category 3, the dispose pattern is to centralize cleanup
depending on whether the cleanup was invoked via the finalizer, or
directly via the IDisposable.Dispose() method.

Objects in category 3 are very rare: you are unlikely to be implementing
them unless you are wrapping unmanaged resources, e.g. shared
memory-mapped files or direct hardware access.
{
if (!this.disposed)
{
if (disposing)
{
CloseFile();
//are there anything else you need to free up
here?????

}
}

this.disposed = true;

You don't need to flag the object as disposed if you are simply using
this in the "recursive IDisposable" scenario: i.e. if this class is
implementing IDisposable simply to propagate Dispose() calls to the
inner XmlTextReader, then the flag is not needed. It is safe to call
Dispose() multiple times on the inner XmlTextReader (it's always safe to
call Dispose() multiple times).
}

ClassA()
{
Dispose(false);
}

This is calling Dispose in the constructor? Or is this meant to be a
finalizer?



-- Barry
 
P

phl

Hi Barry,

Thanks for the great info! Sorry for confusion, on your last question,
the code should be:
~ClassA()
{
Dispose(false);
}

Yes, my CloseFile() routine makes no sense and should be made private.

This is the msdn link
http://msdn.microsoft.com/library/d...ref/html/frlrfsystemidisposableclasstopic.asp
- inregards to Component Class being used, without much explaination.

What I want to do is release the handle to an opened file, while
implemmenting IDisposable. This is my brief overview of garbage
collection, so correct me if I am wrong. I want to be deterministic
about the closing of my file. To do this I can implement a nice Dispose
pattern using the IDisposable interface. So I go and close my file in
my Dispose method and afterwards call GC.SuppressFinalize(this); . The
way I understand this is that when I call GC.SuppressFinalize(this), I
am telling the framwork to take my object off the finalise queue. So my
concern is if I don't deallocate all memory I have used.... in this
case I have declared also a boolean variable in my class, does the
..net runtime know that it's supposed to free up the memory allocated
for this boolean variable? So by taking my object of the finalise
queue, hence causing to be missed my the garbage collector, do I have
to deallocate every bit of memory I have use?
 
B

Barry Kelly

phl said:
What I want to do is release the handle to an opened file

Presumably opened (ultimately) via FileStream.
, while
implemmenting IDisposable. This is my brief overview of garbage
collection, so correct me if I am wrong. I want to be deterministic
about the closing of my file. To do this I can implement a nice Dispose
pattern using the IDisposable interface. So I go and close my file in
my Dispose method

That is good as far as it goes.
and afterwards call GC.SuppressFinalize(this);

To close a file opened via FileStream, where your object is the only
object which has a reference to this FileStream object, you do not call
GC.SuppressFinalize, because you don't need a finalizer.
. The
way I understand this is that when I call GC.SuppressFinalize(this), I
am telling the framwork to take my object off the finalise queue.

The finalize queue is *only* for objects which implement a finalizer.
Any object which only uses unmanaged resources via managed classes (such
as FileStream) does *not* need to implement a finalizer.
So my
concern is if I don't deallocate all memory I have used....

You don't need to deallocate memory. The GC specifically does this (and
pretty much only guarantees this).
in this
case I have declared also a boolean variable in my class, does the
.net runtime know that it's supposed to free up the memory allocated
for this boolean variable?

You don't need to worry about that. For one thing, the boolean is a .NET
value type and is allocated as part of the object memory, so it will be
fried when the object is freed.
So by taking my object of the finalise
queue, hence causing to be missed my the garbage collector, do I have
to deallocate every bit of memory I have use?

You do not need to implement IDisposable or a finalizer to free memory.
The GC does this for you.

-- Barry
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top