Memory question

  • Thread starter Thread starter Michael Rodriguez
  • Start date Start date
M

Michael Rodriguez

Suppose I have a dataset, dsMain, that is already filled with data. What
then, is the affect of this:

DataSet ds1 = dsMain;

Does this cause ds1 to simply become a pointer to dsMain? If so, how is
this code different:

DataSet ds1 = new DataSet();
ds1 = dsMain;

Does ds1 now contain a copy of dsMain? Also, should I call ds1.Dispose() in
both examples, or only in the second one?

TIA,

Mike Rodriguez
 
Michael,

When you do this:

DataSet ds1 = dsMain;

You are assigning ds1 a reference to whatever dsMain is pointing to. A
copy is not made.

When you do this:

DataSet ds1 = new DataSet();
ds1 = dsMain;

You create a new data set, and then that dataset becomes eligible for
garbage collection once you assign the reference dsMain to ds1. In both
instances you are only holding a reference, a copy is not made.

Technically, you should call Dispose on anything that implements
IDisposable. However, I believe that the data set only has that
implementation because of it deriving from MarshalByValueComponent, and it
doesn't really do anything (there is no override of Dispose(boolean) that I
can see).

Hope this helps.
 
Hi Michael,
DataSet ds1 = dsMain;

Does this cause ds1 to simply become a pointer to dsMain?
Yep.

If so, how is this code different:

DataSet ds1 = new DataSet();
ds1 = dsMain;

Does ds1 now contain a copy of dsMain?

Nope, still a pointer to dsMain. The blank DataSet instance you have created
has now no references and will be reclaimed by the Garbage Collector.
Also, should I call ds1.Dispose() in both examples, or only in the second
one?

You should not call Dispose() at all. Dispose() does not release managed
memory, Dispose() makes sure that unmanaged resources are released properly.
 
You should not call Dispose() at all.

Whoa! DataSet implements IDisposable. My understanding is that it is
"good practice" to call Dispose() on any IDisposable object that you
are discarding. So, if I have heard right, "good practice" (as useless
as it might be) in this case would be:

DataSet ds1 = new DataSet();
ds1.Dispose();
ds1 = dsMain;

As Nicholas pointed out, it does not appear that DataSet does anything
in its Dispose() method, but as a caller I can't rely on that. DataSet
in .NET 2.0 (or 2.1, or 3.0) might decide to add some code to its
Dispose method. According to the contract, I _should_ be calling
Dispose() to dispose of a DataSet (in those situations in which I can
know that I hold the last reference to it). To do anything else would
be to peek behind the veil, and it may come back to burn me later.

Or do I have this all wrong?
 
Bruce,

You do not have this wrong, I would say that you elaborated very well
the reason why you ^should^ call Dispose. Dmytro is wrong in this case,
IMO.
 
Hi,


Michael Rodriguez said:
Suppose I have a dataset, dsMain, that is already filled with data. What
then, is the affect of this:

DataSet ds1 = dsMain;

Does this cause ds1 to simply become a pointer to dsMain? If so, how is
this code different:

Yes, both will hold a reference to the same instance.
DataSet ds1 = new DataSet();
ds1 = dsMain;

the dataset instance previously being reference by ds1 is not longer
referenced and hence becomes marked to be GC.



cheers,
 
Thanks to everyone for all the speedy replies!


Ignacio Machin ( .NET/ C# MVP ) said:
Hi,




Yes, both will hold a reference to the same instance.


the dataset instance previously being reference by ds1 is not longer
referenced and hence becomes marked to be GC.



cheers,
 
Hi,

Then the question is why does it implement it?
It's MarshalByValueComponent the one you implements it and DataSet derive
from it.


cheers,


--
Ignacio Machin,
ignacio.machin AT dot.state.fl.us
Florida Department Of Transportation


Nicholas Paldino said:
Bruce,

You do not have this wrong, I would say that you elaborated very well
the reason why you ^should^ call Dispose. Dmytro is wrong in this case,
IMO.

--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Bruce Wood said:
Whoa! DataSet implements IDisposable. My understanding is that it is
"good practice" to call Dispose() on any IDisposable object that you
are discarding. So, if I have heard right, "good practice" (as useless
as it might be) in this case would be:

DataSet ds1 = new DataSet();
ds1.Dispose();
ds1 = dsMain;

As Nicholas pointed out, it does not appear that DataSet does anything
in its Dispose() method, but as a caller I can't rely on that. DataSet
in .NET 2.0 (or 2.1, or 3.0) might decide to add some code to its
Dispose method. According to the contract, I _should_ be calling
Dispose() to dispose of a DataSet (in those situations in which I can
know that I hold the last reference to it). To do anything else would
be to peek behind the veil, and it may come back to burn me later.

Or do I have this all wrong?
 
Ignacio,

The reason it implements it through the base class is that the designers
of the framework didn't know whether or not the components that would be
created later would have the need for disposing. Instead of leaving it up
to the individual component vendors, they felt it best that they just bake
it into the base class for all components (the Component class and the
MarshalByValueComponent class).


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Ignacio Machin ( .NET/ C# MVP ) said:
Hi,

Then the question is why does it implement it?
It's MarshalByValueComponent the one you implements it and DataSet derive
from it.


cheers,


--
Ignacio Machin,
ignacio.machin AT dot.state.fl.us
Florida Department Of Transportation


Nicholas Paldino said:
Bruce,

You do not have this wrong, I would say that you elaborated very well
the reason why you ^should^ call Dispose. Dmytro is wrong in this case,
IMO.

--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Bruce Wood said:
You should not call Dispose() at all.

Whoa! DataSet implements IDisposable. My understanding is that it is
"good practice" to call Dispose() on any IDisposable object that you
are discarding. So, if I have heard right, "good practice" (as useless
as it might be) in this case would be:

DataSet ds1 = new DataSet();
ds1.Dispose();
ds1 = dsMain;

As Nicholas pointed out, it does not appear that DataSet does anything
in its Dispose() method, but as a caller I can't rely on that. DataSet
in .NET 2.0 (or 2.1, or 3.0) might decide to add some code to its
Dispose method. According to the contract, I _should_ be calling
Dispose() to dispose of a DataSet (in those situations in which I can
know that I hold the last reference to it). To do anything else would
be to peek behind the veil, and it may come back to burn me later.

Or do I have this all wrong?
 
This brings up an interesting design problem, both from my point of
view and from Microsoft's point of view. Let's look at it from MS's
point of view, because I think it's clearer in that case.

If MS publishes a class (such as DataSet) that implements IDisposable,
they're leaving their options open. Perhaps you really have to call
Dispose() on instances of the class, and perhaps you don't. However,
you _should_, because you never know what might happen to the class
implementation in the future. However, from MS's point of view, the
cost is that all users of that class now have to worry about disposal.
How annoying.

Furthermore, if they ever change a class that must be Dispose()d so
that it's now totally managed code and does not need to be Dispose()d,
they can never remove the IDisposable implementation from that class or
they'll break all of the code out there that took pains to properly
dispose of objects of that class. So, they're stuck for all eternity
having the class be IDisposable when it doesn't really need to be.

However, if MS publishes a class that does not implement IDisposable,
then they are, in effect guaranteeing that for all time the class will
be totally managed and will never need to be disposed. If they add
IDisposable later, they're breaking the contract and legacy code may
not properly dispose of instances of that class under the new
Framework. Bummer.

Perhaps this is why documentation for IDisposable discourages us from
making Dispose methods that _have_ to be called in order that an object
be GC'd. For example, this is why it's "bad style" to use Dispose() to
unhook an object from static events, because then if Dispose() is never
called then the object will never be GC'd. (Not that I never abuse
Dispose() in this way... just that I shouldn't :-)
 
I should have said "One should not call Dispose() to reclaim managed
memory", because the subject of the post is about (I assume, managed)
memory, and the purpose of Dispose() is quite different.
I apologize for being unclear.

--
Sincerely,
Dmytro Lapshyn [Visual Developer - Visual C# MVP]


Nicholas Paldino said:
Bruce,

You do not have this wrong, I would say that you elaborated very well
the reason why you ^should^ call Dispose. Dmytro is wrong in this case,
IMO.

--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Bruce Wood said:
Whoa! DataSet implements IDisposable. My understanding is that it is
"good practice" to call Dispose() on any IDisposable object that you
are discarding. So, if I have heard right, "good practice" (as useless
as it might be) in this case would be:

DataSet ds1 = new DataSet();
ds1.Dispose();
ds1 = dsMain;

As Nicholas pointed out, it does not appear that DataSet does anything
in its Dispose() method, but as a caller I can't rely on that. DataSet
in .NET 2.0 (or 2.1, or 3.0) might decide to add some code to its
Dispose method. According to the contract, I _should_ be calling
Dispose() to dispose of a DataSet (in those situations in which I can
know that I hold the last reference to it). To do anything else would
be to peek behind the veil, and it may come back to burn me later.

Or do I have this all wrong?
 
The difficulty is that as a caller I don't know why a class I'm calling
has implemented Dispose(). Perhaps it did so to release unmanaged
resources it's holding, or, like DataSet, perhaps it only inherited it
from its caller and its Dispose() doesn't really do anything. However,
as I said, as a caller I have no idea why Dispose() is there, so I have
little choice but to call it.

Furthermore, if I do some research and discover that a class like
DataSet has Dispose() only as an artifact of the inheritance hierarchy,
and not because it holds unmanaged resources, then as a user of that
class (and not its author) I can't know whether that will _always_ be
the case in the future. Just because DataSet doesn't really implement
Dispose() right now doesn't mean that it won't in a later release of
the Framework.

So as a caller, I'm stuck. I really should (by rights) be calling
Dispose() wherever I can, because I can't guarantee that a class that
implements IDisposable (or inherits from a class that implements
IDisposable) doesn't now and won't ever need disposing.

As an implementer, you are correct: I should _write_ a Dispose() method
only to release unmanaged resources, or to release objects I'm holding
that themselves implement Dispose() (for the above reasons). Now, I do
abuse Dispose() in my code (sheepish grin)... it's terribly tempting...
but what I've outlined here should be my proper guidelines for
implementing it.

Nonetheless, if I inherit from a class that has a Dispose() method,
then even if my child class doesn't override it, as a caller I should
still Dispose() instances of the child class, because I don't know why
the base class implemented IDisposable, so I have to Dispose()
instances of the class for the benefit of the base class.
 
Back
Top