By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
458,107 Members | 1,221 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 458,107 IT Pros & Developers. It's quick & easy.

Pls HELP!- DataSet Inherited object not finalizing

P: n/a
Hi All,
I got a issue here and hope someone can help me:
Let's consider this code:

// =================== CODE START =================================
using System;
using System.Data;

namespace TestNamespace
{
public class Test :DataSet
{
public static int i = 0;
public Test():base(){i++;}
~Test(){i--;}
}

public class MainClass
{
[STAThread]
public static void Main(string[] args)
{
Console.WriteLine("Generating Garbage:");
for (int i = 0 ; i < 10 ; i ++) {
Test t = new Test();
}
Console.WriteLine("Collecting Garbage: " + Test.i.ToString());

GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine("Objects not finalized: "+ Test.i.ToString());
}
}
}
// =================== CODE END ===================================

This will compile into a console app - you can just copy and paste in a cs file.

So, if you run this, you will see that Test objects are created but never finalized.
Now, if you comment out ":DataSet" (to NOT inherit from DataSet),
all created Test objects are finalized fine.

I guess my mistake is in the way i inherit from DataSet, but can't figure out what exactly..

Any ideas would be appreciated!!!

Thank you,
Andrey
Nov 16 '05 #1
Share this Question
Share on Google+
35 Replies


P: n/a
MuZZy,

Are you running the debug version of the program, or the release? When
in debug mode, the compiler will generate code (I believe) that does not
release references until the stack is destroyed.

In release mode, it should recognize that the variable t is no longer
used, and you should get the output you are looking for.

Hope this helps.
--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com

"MuZZy" <le*******@yahoo.com> wrote in message
news:Ue********************@comcast.com...
Hi All,
I got a issue here and hope someone can help me:
Let's consider this code:

// =================== CODE START =================================
using System;
using System.Data;

namespace TestNamespace
{
public class Test :DataSet
{
public static int i = 0;
public Test():base(){i++;}
~Test(){i--;}
}

public class MainClass
{ [STAThread]
public static void Main(string[] args)
{
Console.WriteLine("Generating Garbage:");
for (int i = 0 ; i < 10 ; i ++) {
Test t = new Test();
}
Console.WriteLine("Collecting Garbage: " + Test.i.ToString());

GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine("Objects not finalized: "+ Test.i.ToString());
}
}
}
// =================== CODE END ===================================

This will compile into a console app - you can just copy and paste in a cs
file.

So, if you run this, you will see that Test objects are created but never
finalized.
Now, if you comment out ":DataSet" (to NOT inherit from DataSet),
all created Test objects are finalized fine.

I guess my mistake is in the way i inherit from DataSet, but can't figure
out what exactly..

Any ideas would be appreciated!!!

Thank you,
Andrey

Nov 16 '05 #2

P: n/a
A DataSet inherits from MarshallByValueComponent, which implements
IDisposable. Therefore, DataSets are IDisposable. Try implementing the
IDisposable pattern. Trigger the decrement of the counter from the
Dispose() method, don't rely on the finalizer. With non-deterministic
finalization you shouldn't rely on the runtime to execute finalizers in any
particular time frame or in any particular sequence.

So in your main() you would do either of the following with your test
instances:

Test t = new Test();
t.Dispose();

//or

using (Test t = new Test()) {}

--Bob

"MuZZy" <le*******@yahoo.com> wrote in message
news:Ue********************@comcast.com...
Hi All,
I got a issue here and hope someone can help me:
Let's consider this code:

// =================== CODE START =================================
using System;
using System.Data;

namespace TestNamespace
{
public class Test :DataSet
{
public static int i = 0;
public Test():base(){i++;}
~Test(){i--;}
}

public class MainClass
{ [STAThread]
public static void Main(string[] args)
{
Console.WriteLine("Generating Garbage:");
for (int i = 0 ; i < 10 ; i ++) {
Test t = new Test();
}
Console.WriteLine("Collecting Garbage: " + Test.i.ToString());

GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine("Objects not finalized: "+ Test.i.ToString());
}
}
}
// =================== CODE END ===================================

This will compile into a console app - you can just copy and paste in a cs
file.

So, if you run this, you will see that Test objects are created but never
finalized.
Now, if you comment out ":DataSet" (to NOT inherit from DataSet),
all created Test objects are finalized fine.

I guess my mistake is in the way i inherit from DataSet, but can't figure
out what exactly..

Any ideas would be appreciated!!!

Thank you,
Andrey

Nov 16 '05 #3

P: n/a


"MuZZy" <le*******@yahoo.com> wrote in message
news:Ue********************@comcast.com...
Hi All,
I got a issue here and hope someone can help me: I guess my mistake is in the way i inherit from DataSet, but can't figure
out what exactly..

Any ideas would be appreciated!!!

Thank you,
Andrey


This is the intended behavior as the Dataset ctor calls
SuppressFinalize(this).
What exactly are you trying to achieve?

Willy.
Nov 16 '05 #4

P: n/a
Nicholas Paldino [.NET/C# MVP] wrote:
MuZZy,

Are you running the debug version of the program, or the release? When
in debug mode, the compiler will generate code (I believe) that does not
release references until the stack is destroyed.

In release mode, it should recognize that the variable t is no longer
used, and you should get the output you are looking for.

Hope this helps.


Hi Nicholas,

This problem only happens if i inheit from DataSet or DataTable. If i inherit from whatever else,
everything is fine.

BTW, i tried in Release mode - same thing

Andrey
Nov 16 '05 #5

P: n/a
Willy Denoyette [MVP] wrote:
"MuZZy" <le*******@yahoo.com> wrote in message
news:Ue********************@comcast.com...
Hi All,
I got a issue here and hope someone can help me:


I guess my mistake is in the way i inherit from DataSet, but can't figure
out what exactly..

Any ideas would be appreciated!!!

Thank you,
Andrey

This is the intended behavior as the Dataset ctor calls
SuppressFinalize(this).
What exactly are you trying to achieve?

Willy.


Thank you for reply Willy!

Damn, it that's true, i'm screwed!
The thing is that we have the whole framework for our applications, and a class inherited from
DataSet is the core class there.

I just came to the company and i was assigned the bug - memory leaks. I found that it happens
because objects of this class don't get finalized - finalize function has a lot of memory cleaning.

The worst thing is that i can't move all the stuff in Dispose(), as Dispose() is not called for the
object and to find all the places where to put Dispose() would take months if not years...

Can i re-register the inheritd class for the finalization?

Thank you,
Andrey
Nov 16 '05 #6

P: n/a
Bob Grommes wrote:
A DataSet inherits from MarshallByValueComponent, which implements
IDisposable. Therefore, DataSets are IDisposable. Try implementing the
IDisposable pattern. Trigger the decrement of the counter from the
Dispose() method, don't rely on the finalizer. With non-deterministic
finalization you shouldn't rely on the runtime to execute finalizers in any
particular time frame or in any particular sequence.
Hi Bob,
Thank you for replying!

I have to correct you - finalization is pretty deterministic in my case:
If you call GC.WaitForPendingFinalizers, this function will not return until all pending Finalize
functions of collected objects will execute.

So in your main() you would do either of the following with your test
instances:

Test t = new Test();
t.Dispose();

//or

using (Test t = new Test()) {}

--Bob

"MuZZy" <le*******@yahoo.com> wrote in message
news:Ue********************@comcast.com...
Hi All,
I got a issue here and hope someone can help me:
Let's consider this code:

// =================== CODE START =================================
using System;
using System.Data;

namespace TestNamespace
{
public class Test :DataSet
{
public static int i = 0;
public Test():base(){i++;}
~Test(){i--;}
}

public class MainClass
{ [STAThread]
public static void Main(string[] args)
{
Console.WriteLine("Generating Garbage:");
for (int i = 0 ; i < 10 ; i ++) {
Test t = new Test();
}
Console.WriteLine("Collecting Garbage: " + Test.i.ToString());

GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine("Objects not finalized: "+ Test.i.ToString());
}
}
}
// =================== CODE END ===================================

This will compile into a console app - you can just copy and paste in a cs
file.

So, if you run this, you will see that Test objects are created but never
finalized.
Now, if you comment out ":DataSet" (to NOT inherit from DataSet),
all created Test objects are finalized fine.

I guess my mistake is in the way i inherit from DataSet, but can't figure
out what exactly..

Any ideas would be appreciated!!!

Thank you,
Andrey


Nov 16 '05 #7

P: n/a
MuZZy,

I am curious, what are you doing with the data set which requires
explicit management of memory in the finalizer and Dispose? Considering
that it should all be managed objects, you shouldn't have an issue. If you
just release the reference, let GC handle the memory.

--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com
"MuZZy" <le*******@yahoo.com> wrote in message
news:1Z********************@comcast.com...
Willy Denoyette [MVP] wrote:
"MuZZy" <le*******@yahoo.com> wrote in message
news:Ue********************@comcast.com...
Hi All,
I got a issue here and hope someone can help me:


I guess my mistake is in the way i inherit from DataSet, but can't figure
out what exactly..

Any ideas would be appreciated!!!

Thank you,
Andrey

This is the intended behavior as the Dataset ctor calls
SuppressFinalize(this).
What exactly are you trying to achieve?

Willy.


Thank you for reply Willy!

Damn, it that's true, i'm screwed!
The thing is that we have the whole framework for our applications, and a
class inherited from DataSet is the core class there.

I just came to the company and i was assigned the bug - memory leaks. I
found that it happens because objects of this class don't get finalized -
finalize function has a lot of memory cleaning.

The worst thing is that i can't move all the stuff in Dispose(), as
Dispose() is not called for the object and to find all the places where to
put Dispose() would take months if not years...

Can i re-register the inheritd class for the finalization?

Thank you,
Andrey

Nov 16 '05 #8

P: n/a
Nicholas Paldino [.NET/C# MVP] wrote:
MuZZy,

I am curious, what are you doing with the data set which requires
explicit management of memory in the finalizer and Dispose? Considering
that it should all be managed objects, you shouldn't have an issue. If you
just release the reference, let GC handle the memory.

Nicholas,

We are using not DataSet directly but an inherited class.
This class has members of unmanaged C++ STL classes STRMAP, STRSET, STRPAIRVECTOR,
wich need to be explicitly deleted.

BTW, i already fixed the problem after Willy told me about call to GC.SuppressFinalizer() - i needed
to call GC.ReRegisterFinalizer(this) constructor of in my DataSet inheriting class, and it works now.

Thank you,
Andrey
Nov 16 '05 #9

P: n/a
If I remember correctly from the other discussion, he's actually doing
Managed C++, it's a mix of managed and unmanaged code?

to answer the original question, use GC.ReRegisterForFinalize(this), put
that in the Test constructor and it will start getting finalized again.

"Nicholas Paldino [.NET/C# MVP]" wrote:
MuZZy,

I am curious, what are you doing with the data set which requires
explicit management of memory in the finalizer and Dispose? Considering
that it should all be managed objects, you shouldn't have an issue. If you
just release the reference, let GC handle the memory.

--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com
"MuZZy" <le*******@yahoo.com> wrote in message
news:1Z********************@comcast.com...
Willy Denoyette [MVP] wrote:
"MuZZy" <le*******@yahoo.com> wrote in message
news:Ue********************@comcast.com...

Hi All,
I got a issue here and hope someone can help me:
I guess my mistake is in the way i inherit from DataSet, but can't figure
out what exactly..

Any ideas would be appreciated!!!

Thank you,
Andrey
This is the intended behavior as the Dataset ctor calls
SuppressFinalize(this).
What exactly are you trying to achieve?

Willy.


Thank you for reply Willy!

Damn, it that's true, i'm screwed!
The thing is that we have the whole framework for our applications, and a
class inherited from DataSet is the core class there.

I just came to the company and i was assigned the bug - memory leaks. I
found that it happens because objects of this class don't get finalized -
finalize function has a lot of memory cleaning.

The worst thing is that i can't move all the stuff in Dispose(), as
Dispose() is not called for the object and to find all the places where to
put Dispose() would take months if not years...

Can i re-register the inheritd class for the finalization?

Thank you,
Andrey


Nov 16 '05 #10

P: n/a
Andrey,

It's good that the problem is fixed.

However, I would urge you to implement the IDisposable interface (or
override the protected Dispose method if it is already there) so that it
will release the unmanaged elements of the class. Your overall app
performance is probably affected in some way as a result of the unmanaged
memory sitting around until finalization.

Of course, there is the general concept of adhering to best practices.
Just ignoring implementations of IDispose is generally not a good thing.
--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com

"MuZZy" <le*******@yahoo.com> wrote in message
news:e4********************@comcast.com...
Nicholas Paldino [.NET/C# MVP] wrote:
MuZZy,

I am curious, what are you doing with the data set which requires
explicit management of memory in the finalizer and Dispose? Considering
that it should all be managed objects, you shouldn't have an issue. If
you just release the reference, let GC handle the memory.

Nicholas,

We are using not DataSet directly but an inherited class.
This class has members of unmanaged C++ STL classes STRMAP, STRSET,
STRPAIRVECTOR,
wich need to be explicitly deleted.

BTW, i already fixed the problem after Willy told me about call to
GC.SuppressFinalizer() - i needed to call GC.ReRegisterFinalizer(this)
constructor of in my DataSet inheriting class, and it works now.

Thank you,
Andrey

Nov 16 '05 #11

P: n/a
MuZZy <le*******@yahoo.com> wrote:
Damn, it that's true, i'm screwed! The thing is that we have the
whole framework for our applications, and a class inherited from
DataSet is the core class there.


You can always use GC.ReRegisterForFinalize. Relying on finalizers
really is a nasty solution though, IMO.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #12

P: n/a

"MuZZy" <le*******@yahoo.com> wrote in message
news:1Z********************@comcast.com...

Damn, it that's true, i'm screwed!
The thing is that we have the whole framework for our applications, and a
class inherited from DataSet is the core class there.

I just came to the company and i was assigned the bug - memory leaks. I
found that it happens because objects of this class don't get finalized -
finalize function has a lot of memory cleaning.

The worst thing is that i can't move all the stuff in Dispose(), as
Dispose() is not called for the object and to find all the places where to
put Dispose() would take months if not years...

Can i re-register the inheritd class for the finalization?

Thank you,
Andrey


A Dataset is a pure managed resource, So there is nothing extra to be done
when the GC run's. If the instance becomes eligible for collection it will
be removed from the managed heap at the next GC run.
Make sure you remove the DataTable(s) from the dataset when done with it,
failing to do so will keep the DataSet and Table references live and as such
the memory taken by the tables Row data. Calling Dispose() on both
DataTables and DataSet wont help to release managed memory as you probably
know by now.

And, no you can't re-register, what do you think you could do in the
Finalizer that isn't done by the GC?

Willy.


Nov 16 '05 #13

P: n/a
Sorry, should read
.....
And, no you shouldn't re-register, ....

Willy.

"Willy Denoyette [MVP]" <wi*************@pandora.be> wrote in message
news:%2******************@TK2MSFTNGP15.phx.gbl...

"MuZZy" <le*******@yahoo.com> wrote in message
news:1Z********************@comcast.com...

Damn, it that's true, i'm screwed!
The thing is that we have the whole framework for our applications, and a
class inherited from DataSet is the core class there.

I just came to the company and i was assigned the bug - memory leaks. I
found that it happens because objects of this class don't get finalized -
finalize function has a lot of memory cleaning.

The worst thing is that i can't move all the stuff in Dispose(), as
Dispose() is not called for the object and to find all the places where
to put Dispose() would take months if not years...

Can i re-register the inheritd class for the finalization?

Thank you,
Andrey


A Dataset is a pure managed resource, So there is nothing extra to be done
when the GC run's. If the instance becomes eligible for collection it will
be removed from the managed heap at the next GC run.
Make sure you remove the DataTable(s) from the dataset when done with it,
failing to do so will keep the DataSet and Table references live and as
such the memory taken by the tables Row data. Calling Dispose() on both
DataTables and DataSet wont help to release managed memory as you probably
know by now.

And, no you can't re-register, what do you think you could do in the
Finalizer that isn't done by the GC?

Willy.

Nov 16 '05 #14

P: n/a
Nicholas Paldino [.NET/C# MVP] wrote:
Andrey,

It's good that the problem is fixed.

However, I would urge you to implement the IDisposable interface (or
override the protected Dispose method if it is already there) so that it
will release the unmanaged elements of the class. Your overall app
performance is probably affected in some way as a result of the unmanaged
memory sitting around until finalization.

Of course, there is the general concept of adhering to best practices.
Just ignoring implementations of IDispose is generally not a good thing.


I agree on that, i always try to implement IDisposed
But again,i got into th eproject after it's being developed and sold for two nad a half years,
so we really can't redo it all over.

ANdrey
Nov 16 '05 #15

P: n/a
Daniel Jin wrote:
If I remember correctly from the other discussion, he's actually doing
Managed C++, it's a mix of managed and unmanaged code?

to answer the original question, use GC.ReRegisterForFinalize(this), put
that in the Test constructor and it will start getting finalized again.
It's done and working now!

"Nicholas Paldino [.NET/C# MVP]" wrote:

MuZZy,

I am curious, what are you doing with the data set which requires
explicit management of memory in the finalizer and Dispose? Considering
that it should all be managed objects, you shouldn't have an issue. If you
just release the reference, let GC handle the memory.

--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com
"MuZZy" <le*******@yahoo.com> wrote in message
news:1Z********************@comcast.com...
Willy Denoyette [MVP] wrote:

"MuZZy" <le*******@yahoo.com> wrote in message
news:Ue********************@comcast.com...
>Hi All,
>I got a issue here and hope someone can help me:
>I guess my mistake is in the way i inherit from DataSet, but can't figure
>out what exactly..
>
>Any ideas would be appreciated!!!
>
>Thank you,
>Andrey
This is the intended behavior as the Dataset ctor calls
SuppressFinalize(this).
What exactly are you trying to achieve?

Willy.

Thank you for reply Willy!

Damn, it that's true, i'm screwed!
The thing is that we have the whole framework for our applications, and a
class inherited from DataSet is the core class there.

I just came to the company and i was assigned the bug - memory leaks. I
found that it happens because objects of this class don't get finalized -
finalize function has a lot of memory cleaning.

The worst thing is that i can't move all the stuff in Dispose(), as
Dispose() is not called for the object and to find all the places where to
put Dispose() would take months if not years...

Can i re-register the inheritd class for the finalization?

Nov 16 '05 #16

P: n/a
Jon Skeet [C# MVP] wrote:
MuZZy <le*******@yahoo.com> wrote:
Damn, it that's true, i'm screwed! The thing is that we have the
whole framework for our applications, and a class inherited from
DataSet is the core class there.

You can always use GC.ReRegisterForFinalize. Relying on finalizers
really is a nasty solution though, IMO.

Strongly agree! But that's the way the app is done...
Nov 16 '05 #17

P: n/a
Willy Denoyette [MVP] wrote:
Sorry, should read
....
And, no you shouldn't re-register, ....

I just re-registered and it seems to release those objects, at lease ~Test fires MessageBox.Show()
in test.

Is there a reason i shouldn't re-register? Note, i re-register not DataSet objects, but objects of
class inherited from DataSet... Anyway, what's the reason? And is it critical?

Thank you!
Willy.

"Willy Denoyette [MVP]" <wi*************@pandora.be> wrote in message
news:%2******************@TK2MSFTNGP15.phx.gbl...
"MuZZy" <le*******@yahoo.com> wrote in message
news:1Z********************@comcast.com...

Damn, it that's true, i'm screwed!
The thing is that we have the whole framework for our applications, and a
class inherited from DataSet is the core class there.

I just came to the company and i was assigned the bug - memory leaks. I
found that it happens because objects of this class don't get finalized -
finalize function has a lot of memory cleaning.

The worst thing is that i can't move all the stuff in Dispose(), as
Dispose() is not called for the object and to find all the places where
to put Dispose() would take months if not years...

Can i re-register the inheritd class for the finalization?

Thank you,
Andrey


A Dataset is a pure managed resource, So there is nothing extra to be done
when the GC run's. If the instance becomes eligible for collection it will
be removed from the managed heap at the next GC run.
Make sure you remove the DataTable(s) from the dataset when done with it,
failing to do so will keep the DataSet and Table references live and as
such the memory taken by the tables Row data. Calling Dispose() on both
DataTables and DataSet wont help to release managed memory as you probably
know by now.

And, no you can't re-register, what do you think you could do in the
Finalizer that isn't done by the GC?

Willy.

Nov 16 '05 #18

P: n/a

"MuZZy" <le*******@yahoo.com> wrote in message
news:vc********************@comcast.com...
Willy Denoyette [MVP] wrote:
Sorry, should read
....
And, no you shouldn't re-register, ....


I just re-registered and it seems to release those objects, at lease ~Test
fires MessageBox.Show() in test.

Is there a reason i shouldn't re-register? Note, i re-register not DataSet
objects, but objects of class inherited from DataSet... Anyway, what's the
reason? And is it critical?

Thank you!


Well it depends what you are doing in your finalizer, if all you are doing
is decrement a shared variable it's a waste of resources (finalizers are
expensive to run), if you are releasing unmanaged resources YOU OWN, it's
something that should be done in your Dispose method.
But re-registering will certainly NOT release the resources held by the
DataSet and it's contained objects, that's taken care of by the GC not the
Finalizer!!!

Willy.
Nov 16 '05 #19

P: n/a

"MuZZy" <le*******@yahoo.com> wrote in message
news:vc********************@comcast.com...
Daniel Jin wrote:
If I remember correctly from the other discussion, he's actually doing
Managed C++, it's a mix of managed and unmanaged code?

to answer the original question, use GC.ReRegisterForFinalize(this), put
that in the Test constructor and it will start getting finalized again.


It's done and working now!


What exactly do you mean by it's working?
Are the memory leaks gone?

Willy.
Nov 16 '05 #20

P: n/a
Willy Denoyette [MVP] wrote:
"MuZZy" <le*******@yahoo.com> wrote in message
news:vc********************@comcast.com...
Willy Denoyette [MVP] wrote:
Sorry, should read
....
And, no you shouldn't re-register, ....


I just re-registered and it seems to release those objects, at lease ~Test
fires MessageBox.Show() in test.

Is there a reason i shouldn't re-register? Note, i re-register not DataSet
objects, but objects of class inherited from DataSet... Anyway, what's the
reason? And is it critical?

Thank you!

Well it depends what you are doing in your finalizer, if all you are doing
is decrement a shared variable it's a waste of resources (finalizers are
expensive to run), if you are releasing unmanaged resources YOU OWN, it's
something that should be done in your Dispose method.
But re-registering will certainly NOT release the resources held by the
DataSet and it's contained objects, that's taken care of by the GC not the
Finalizer!!!

In finalizer i destroy unmanaged c++ objects of types STRMAP, STRPAIRVECTOR, etc. which are STL
types defines.

Again, i know i should do it in Dispose(), but that's not an option now as fixing it in all places
woul dtake me more than a year with hundreds of classes using this derived from DataSet class.

So i have to work with what i have unfotunately...


Nov 16 '05 #21

P: n/a
Willy Denoyette [MVP] wrote:
"MuZZy" <le*******@yahoo.com> wrote in message
news:vc********************@comcast.com...
Daniel Jin wrote:
If I remember correctly from the other discussion, he's actually doing
Managed C++, it's a mix of managed and unmanaged code?

to answer the original question, use GC.ReRegisterForFinalize(this), put
that in the Test constructor and it will start getting finalized again.


It's done and working now!

What exactly do you mean by it's working?
Are the memory leaks gone?

Willy.


Well, under "it's done!" i meant that objects get finalized, i see it because the static counter
decreases.
But no, memory leaks aren't gone.. and that seems to be a much bigger issue...

Oh man, my brain is on fire!

Nov 16 '05 #22

P: n/a

"MuZZy" <le*******@yahoo.com> wrote in message
news:kL********************@comcast.com...
Willy Denoyette [MVP] wrote:
"MuZZy" <le*******@yahoo.com> wrote in message
news:vc********************@comcast.com...
Willy Denoyette [MVP] wrote:

Sorry, should read
....
And, no you shouldn't re-register, ....
I just re-registered and it seems to release those objects, at lease
~Test fires MessageBox.Show() in test.

Is there a reason i shouldn't re-register? Note, i re-register not
DataSet objects, but objects of class inherited from DataSet... Anyway,
what's the reason? And is it critical?

Thank you!

Well it depends what you are doing in your finalizer, if all you are
doing is decrement a shared variable it's a waste of resources
(finalizers are expensive to run), if you are releasing unmanaged
resources YOU OWN, it's something that should be done in your Dispose
method.
But re-registering will certainly NOT release the resources held by the
DataSet and it's contained objects, that's taken care of by the GC not
the Finalizer!!!

In finalizer i destroy unmanaged c++ objects of types STRMAP,
STRPAIRVECTOR, etc. which are STL types defines.

Again, i know i should do it in Dispose(), but that's not an option now as
fixing it in all places woul dtake me more than a year with hundreds of
classes using this derived from DataSet class.

So i have to work with what i have unfotunately...


I told you before and I suggest you again;

- forget the finalizer, your problem is not related to this!!
Using the performance manager, watch the Gen0, 1, 2 and large heap (LH)
allocations (CLR memory counters), when done with the DataSet (extended) and
you remove all tables from the DS, you will see that all counters drop to a
reasonable low level after a GC run (you can try by calling GC.Collect),
however if you fail to remove the DataTables there is nothing to collect as
the DataTables still hold a reference to the DS and the DS still holds
references to the contained tables.

Willy.


Nov 16 '05 #23

P: n/a
Willy Denoyette [MVP] wrote:
"MuZZy" <le*******@yahoo.com> wrote in message
news:kL********************@comcast.com...
Willy Denoyette [MVP] wrote:
"MuZZy" <le*******@yahoo.com> wrote in message
news:vc********************@comcast.com...
Willy Denoyette [MVP] wrote:
>Sorry, should read
>....
>And, no you shouldn't re-register, ....
>

I just re-registered and it seems to release those objects, at lease
~Test fires MessageBox.Show() in test.

Is there a reason i shouldn't re-register? Note, i re-register not
DataSet objects, but objects of class inherited from DataSet... Anyway,
what's the reason? And is it critical?

Thank you!

Well it depends what you are doing in your finalizer, if all you are
doing is decrement a shared variable it's a waste of resources
(finalizers are expensive to run), if you are releasing unmanaged
resources YOU OWN, it's something that should be done in your Dispose
method.
But re-registering will certainly NOT release the resources held by the
DataSet and it's contained objects, that's taken care of by the GC not
the Finalizer!!!


In finalizer i destroy unmanaged c++ objects of types STRMAP,
STRPAIRVECTOR, etc. which are STL types defines.

Again, i know i should do it in Dispose(), but that's not an option now as
fixing it in all places woul dtake me more than a year with hundreds of
classes using this derived from DataSet class.

So i have to work with what i have unfotunately...

I told you before and I suggest you again;

- forget the finalizer, your problem is not related to this!!
Using the performance manager, watch the Gen0, 1, 2 and large heap (LH)
allocations (CLR memory counters), when done with the DataSet (extended) and
you remove all tables from the DS, you will see that all counters drop to a
reasonable low level after a GC run (you can try by calling GC.Collect),
however if you fail to remove the DataTables there is nothing to collect as
the DataTables still hold a reference to the DS and the DS still holds
references to the contained tables.


Your last statement about DataTable refs and DataSet refs is very interesting.
Could you give me a bit more explanation on what you mean?

Do you mean that if i don't clear DataSetExtended->Tables->Clear() it won't be GC'd?
Even if i do DataSetExtended = null; ?
Why? The obect is dereferenced, Tables are contained in it, reference is internal...

AM I MISSING SOMETHING??? I know i am :( Pls HELP!!!
I'm going nuts with app, frankly :(

Nov 16 '05 #24

P: n/a
Willy Denoyette [MVP] <wi*************@pandora.be> wrote:
I told you before and I suggest you again;

- forget the finalizer, your problem is not related to this!!
It is, if they were relying on the finalizer to release unmanaged
resources.
Using the performance manager, watch the Gen0, 1, 2 and large heap (LH)
allocations (CLR memory counters), when done with the DataSet (extended) and
you remove all tables from the DS, you will see that all counters drop to a
reasonable low level after a GC run (you can try by calling GC.Collect),
however if you fail to remove the DataTables there is nothing to collect as
the DataTables still hold a reference to the DS and the DS still holds
references to the contained tables.


I don't think that's the problem, as he's now seeing the DataSets being
finalized.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #25

P: n/a
See inline ***

Willy.

"Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message
news:MP************************@msnews.microsoft.c om...
Willy Denoyette [MVP] <wi*************@pandora.be> wrote:
I told you before and I suggest you again;

- forget the finalizer, your problem is not related to this!!
It is, if they were relying on the finalizer to release unmanaged
resources.

*** Sure, I didn't say the finalizer was useless, I said it won't release
the DataSet objects.
Using the performance manager, watch the Gen0, 1, 2 and large heap (LH)
allocations (CLR memory counters), when done with the DataSet (extended)
and
you remove all tables from the DS, you will see that all counters drop to
a
reasonable low level after a GC run (you can try by calling GC.Collect),
however if you fail to remove the DataTables there is nothing to collect
as
the DataTables still hold a reference to the DS and the DS still holds
references to the contained tables.


I don't think that's the problem, as he's now seeing the DataSets being
finalized.


*** No, he's not seeing the DataSet's being released, he's seeing the
finalizer being called (check it's reply dated 23:53 on this thread).
--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too


Nov 16 '05 #26

P: n/a

"MuZZy" <le*******@yahoo.com> wrote in message
news:pp********************@comcast.com...
Your last statement about DataTable refs and DataSet refs is very
interesting.
Could you give me a bit more explanation on what you mean?

Do you mean that if i don't clear DataSetExtended->Tables->Clear() it
won't be GC'd?
Even if i do DataSetExtended = null; ?
Why? The obect is dereferenced, Tables are contained in it, reference is
internal...

AM I MISSING SOMETHING??? I know i am :( Pls HELP!!!
I'm going nuts with app, frankly :(


I guess, I can better illustrate this by means of a sample.
Compile following code, and run it from the console, start perfmon and watch
the GC counters (CLR memory object).
You will see that as long as the DataSet contains tables, it won't get
collected. Don't forget that the actual size of a DataSet is the size of
it's contained table(s) data.

// Begin
using System;
using System.Data;
class Tester
{
static void Main()
{
using(DataSet custDS = new DataSet("Test"))
{
Console.WriteLine("Start perfmon, select counters and press <Enter> when
done");
Console.ReadLine(); // this gives you the opportunity to start permon
and select the GC counters.
DataTable dt = Build(custDS);
// Check - does the table belongs to a dataset?
if (dt.DataSet != null) // NOTE this property is read-only and holds a
reference to the containing DataSet!!!!
{
Console.WriteLine("Detach all tables");
// Remove tables from the collection,
// comment following statement and watch the perf counters...
dt.DataSet.Tables.Clear();
// or remove a single table from the collection
// dt.DataSet.Tables.Remove (dt);
// Check again...
if (dt.DataSet == null)
Console.WriteLine("DS reference cleared, press <Enter> to force GC");
}
Console.ReadLine();
// Force a collection (only for demo purpose)
GC.Collect();
}
Console.ReadLine();
}
// Fill a table with data and add it to the DataSet
private static DataTable Build(DataSet ds){
DataTable dt = ds.Tables.Add("MyTable");
DataColumn dcol;
DataRow drow;
dcol = new DataColumn();
dcol.DataType = System.Type.GetType("System.Int32");
dcol.ColumnName = "id";
dt.Columns.Add(dcol);
dcol = new DataColumn();
dcol.DataType = Type.GetType("System.String");
dcol.ColumnName = "item";
dt.Columns.Add(dcol);
// Add some data
for(int i = 0; i < 50000; i++){
drow = dt.NewRow();
drow["id"] = i;
drow["item"] = "item " + i;
dt.Rows.Add(drow);
}
return dt;
}
}
// End code

Willy.
Nov 16 '05 #27

P: n/a


"Willy Denoyette [MVP]" wrote:
See inline ***

Willy.

"Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message
news:MP************************@msnews.microsoft.c om...
Willy Denoyette [MVP] <wi*************@pandora.be> wrote:
I told you before and I suggest you again;

- forget the finalizer, your problem is not related to this!!
It is, if they were relying on the finalizer to release unmanaged
resources.

*** Sure, I didn't say the finalizer was useless, I said it won't release
the DataSet objects.


he's not trying to release DataSet in the finalizer. He has a class derived
from DataSet. In this derived class, he has a bunch of unmanaged STL objects
that needs to be released. but because DataSet is supressing the
finalization, the finalizer that attempt to release these STL objects in the
derived class wasn't called. the sample code he supplied that simply
decrements a counter was just a sample to demonstrate his problem. that is
not what he's doing in his real code.
Using the performance manager, watch the Gen0, 1, 2 and large heap (LH)
allocations (CLR memory counters), when done with the DataSet (extended)
and
you remove all tables from the DS, you will see that all counters drop to
a
reasonable low level after a GC run (you can try by calling GC.Collect),
however if you fail to remove the DataTables there is nothing to collect
as
the DataTables still hold a reference to the DS and the DS still holds
references to the contained tables.


I don't think that's the problem, as he's now seeing the DataSets being
finalized.


*** No, he's not seeing the DataSet's being released, he's seeing the
finalizer being called (check it's reply dated 23:53 on this thread).
--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too


Nov 16 '05 #28

P: n/a
if what you are saying is true, then this modified sample should not collect
because the circular reference between DataSet and DataTable, and clearly
that's not the case.

All GC cares about is if the object is reachable from a root object.
DataSet and DataTable can reference each other all they want, and if it's not
reachable from the root, it's garbage and will be collected.

using System;
using System.Data;

namespace TestNamespace
{
public class Test :DataSet
{
public static int i = 0;
public Test():base()
{
i++;
GC.ReRegisterForFinalize(this);
}
~Test(){i--;}
}

public class MainClass
{
[STAThread]
public static void Main(string[] args)
{
Console.WriteLine("Generating Garbage:");
for (int i = 0 ; i < 10 ; i ++) {
Test t = new Test();
t.Tables.Add();
}

Console.WriteLine("Collecting Garbage: " + Test.i.ToString());

GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine("Objects not finalized: "+ Test.i.ToString());

Console.ReadLine();
}
}
}

"Willy Denoyette [MVP]" wrote:

"MuZZy" <le*******@yahoo.com> wrote in message
news:kL********************@comcast.com...
Willy Denoyette [MVP] wrote:
"MuZZy" <le*******@yahoo.com> wrote in message
news:vc********************@comcast.com...

Willy Denoyette [MVP] wrote:

>Sorry, should read
>....
>And, no you shouldn't re-register, ....
>

I just re-registered and it seems to release those objects, at lease
~Test fires MessageBox.Show() in test.

Is there a reason i shouldn't re-register? Note, i re-register not
DataSet objects, but objects of class inherited from DataSet... Anyway,
what's the reason? And is it critical?

Thank you!
Well it depends what you are doing in your finalizer, if all you are
doing is decrement a shared variable it's a waste of resources
(finalizers are expensive to run), if you are releasing unmanaged
resources YOU OWN, it's something that should be done in your Dispose
method.
But re-registering will certainly NOT release the resources held by the
DataSet and it's contained objects, that's taken care of by the GC not
the Finalizer!!!

In finalizer i destroy unmanaged c++ objects of types STRMAP,
STRPAIRVECTOR, etc. which are STL types defines.

Again, i know i should do it in Dispose(), but that's not an option now as
fixing it in all places woul dtake me more than a year with hundreds of
classes using this derived from DataSet class.

So i have to work with what i have unfotunately...


I told you before and I suggest you again;

- forget the finalizer, your problem is not related to this!!
Using the performance manager, watch the Gen0, 1, 2 and large heap (LH)
allocations (CLR memory counters), when done with the DataSet (extended) and
you remove all tables from the DS, you will see that all counters drop to a
reasonable low level after a GC run (you can try by calling GC.Collect),
however if you fail to remove the DataTables there is nothing to collect as
the DataTables still hold a reference to the DS and the DS still holds
references to the contained tables.

Willy.


Nov 16 '05 #29

P: n/a
Your test is flawed.

your using() block is keeping the reference to DataSet around. that's why
detaching DataTable forces the collection on it, without detachment causes
the DataTable not being collected because it's still reachable through a
rooted object (DataSet)

"Willy Denoyette [MVP]" wrote:

"MuZZy" <le*******@yahoo.com> wrote in message
news:pp********************@comcast.com...
Your last statement about DataTable refs and DataSet refs is very
interesting.
Could you give me a bit more explanation on what you mean?

Do you mean that if i don't clear DataSetExtended->Tables->Clear() it
won't be GC'd?
Even if i do DataSetExtended = null; ?
Why? The obect is dereferenced, Tables are contained in it, reference is
internal...

AM I MISSING SOMETHING??? I know i am :( Pls HELP!!!
I'm going nuts with app, frankly :(


I guess, I can better illustrate this by means of a sample.
Compile following code, and run it from the console, start perfmon and watch
the GC counters (CLR memory object).
You will see that as long as the DataSet contains tables, it won't get
collected. Don't forget that the actual size of a DataSet is the size of
it's contained table(s) data.

// Begin
using System;
using System.Data;
class Tester
{
static void Main()
{
using(DataSet custDS = new DataSet("Test"))
{
Console.WriteLine("Start perfmon, select counters and press <Enter> when
done");
Console.ReadLine(); // this gives you the opportunity to start permon
and select the GC counters.
DataTable dt = Build(custDS);
// Check - does the table belongs to a dataset?
if (dt.DataSet != null) // NOTE this property is read-only and holds a
reference to the containing DataSet!!!!
{
Console.WriteLine("Detach all tables");
// Remove tables from the collection,
// comment following statement and watch the perf counters...
dt.DataSet.Tables.Clear();
// or remove a single table from the collection
// dt.DataSet.Tables.Remove (dt);
// Check again...
if (dt.DataSet == null)
Console.WriteLine("DS reference cleared, press <Enter> to force GC");
}
Console.ReadLine();
// Force a collection (only for demo purpose)
GC.Collect();
}
Console.ReadLine();
}
// Fill a table with data and add it to the DataSet
private static DataTable Build(DataSet ds){
DataTable dt = ds.Tables.Add("MyTable");
DataColumn dcol;
DataRow drow;
dcol = new DataColumn();
dcol.DataType = System.Type.GetType("System.Int32");
dcol.ColumnName = "id";
dt.Columns.Add(dcol);
dcol = new DataColumn();
dcol.DataType = Type.GetType("System.String");
dcol.ColumnName = "item";
dt.Columns.Add(dcol);
// Add some data
for(int i = 0; i < 50000; i++){
drow = dt.NewRow();
drow["id"] = i;
drow["item"] = "item " + i;
dt.Rows.Add(drow);
}
return dt;
}
}
// End code

Willy.

Nov 16 '05 #30

P: n/a
I'm watching perfmon and i see that CLR Gen 2 increases dramatically though egenartion 0 and 1 heaps
oscillate around one value
Nov 16 '05 #31

P: n/a

"Daniel Jin" <Da*******@discussions.microsoft.com> wrote in message
news:BB**********************************@microsof t.com...
Your test is flawed.

your using() block is keeping the reference to DataSet around. that's why
detaching DataTable forces the collection on it, without detachment causes
the DataTable not being collected because it's still reachable through a
rooted object (DataSet)


My bad, sorry for this, I should have mentioned this explicitly, but who
tells the they aren't using the same construct. Note that OP said he wasn't
the author of the application, so I only wanted to illustrate (on purpose):
1. the effect of keeping a reference to the DataSet instance, be it in a
scoped using block or something else, and..
2. the effect of releasing the contained table objects on the managed memory
consumption, without the need to release the DataSet object instance.

I did this only to show what OP has to look for and to illustrate how the
performance counters can be used to watch the behavior.

Willy.

Nov 16 '05 #32

P: n/a

"Daniel Jin" <Da*******@discussions.microsoft.com> wrote in message
news:F2**********************************@microsof t.com...


"Willy Denoyette [MVP]" wrote:
See inline ***

Willy.

"Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message
news:MP************************@msnews.microsoft.c om...
> Willy Denoyette [MVP] <wi*************@pandora.be> wrote:
>> I told you before and I suggest you again;
>>
>> - forget the finalizer, your problem is not related to this!!
>
> It is, if they were relying on the finalizer to release unmanaged
> resources.
>

*** Sure, I didn't say the finalizer was useless, I said it won't release
the DataSet objects.


he's not trying to release DataSet in the finalizer. He has a class
derived
from DataSet. In this derived class, he has a bunch of unmanaged STL
objects
that needs to be released. but because DataSet is supressing the
finalization, the finalizer that attempt to release these STL objects in
the
derived class wasn't called. the sample code he supplied that simply
decrements a counter was just a sample to demonstrate his problem. that
is
not what he's doing in his real code.


Sure, but until now he didn't show any real code, and running the finalizer
did not solve his memory leak issue as he replied in another posting.
Problem with OP is that this is not the first (and not the last, actualy he
started a new one) thread on this same issue. In a previous thread he
explicitly said that when running the code through a profiler, it was clear
that the memory was taken by a DataSet, that means it was managed memory so
running the finalizer would not release this (unless some way or another a
reference was held by the unmanaged part).
Another thing I fail to see ( without seeing some code) is why ( and how )
the managed part is freeing unmanaged STL objects.

Willy.
Nov 16 '05 #33

P: n/a
Willy Denoyette [MVP] wrote:
"Daniel Jin" <Da*******@discussions.microsoft.com> wrote in message
news:F2**********************************@microsof t.com...

"Willy Denoyette [MVP]" wrote:

See inline ***

Willy.

"Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message
news:MP************************@msnews.microsof t.com...

Willy Denoyette [MVP] <wi*************@pandora.be> wrote:

>I told you before and I suggest you again;
>
>- forget the finalizer, your problem is not related to this!!

It is, if they were relying on the finalizer to release unmanaged
resources.
*** Sure, I didn't say the finalizer was useless, I said it won't release
the DataSet objects.


he's not trying to release DataSet in the finalizer. He has a class
derived
from DataSet. In this derived class, he has a bunch of unmanaged STL
objects
that needs to be released. but because DataSet is supressing the
finalization, the finalizer that attempt to release these STL objects in
the
derived class wasn't called. the sample code he supplied that simply
decrements a counter was just a sample to demonstrate his problem. that
is
not what he's doing in his real code.

Sure, but until now he didn't show any real code, and running the finalizer
did not solve his memory leak issue as he replied in another posting.
Problem with OP is that this is not the first (and not the last, actualy he
started a new one) thread on this same issue. In a previous thread he
explicitly said that when running the code through a profiler, it was clear
that the memory was taken by a DataSet, that means it was managed memory so
running the finalizer would not release this (unless some way or another a
reference was held by the unmanaged part).
Another thing I fail to see ( without seeing some code) is why ( and how )
the managed part is freeing unmanaged STL objects.

Willy.

Ok, here is the real piece of code:

// In .h file here is the part of class declaration
public __gc class CResSet : public DataSet
{
public:
CResSet(CResSet *rs);
~CResSet();
STRMAP *m_smTables;
STRPAIRVECTOR *m_vp;
STRSET *m_ssPopulated;
<...>
}
// In .cpp file, here is the finalizer releasing unmanaged memory

// constructor
TnrData::CResSet::CResSet()
{
<..>
m_vp = new STRPAIRVECTOR();
m_ssPopulated = new STRSET();
m_smTables = new STRMAP();
<..>
}

// finalizer
TnrData::CResSet::~CResSet()
{
delete m_smTables; // THESE ARE
delete m_vp; // UNMANAGED STL
delete m_ssPopulated; // OBJECTS

Counter--;
for (int i = 0 ; i < Numbers->Count; i++)
{
Object *o = Numbers->get_Item(i);
int iii = Convert::ToInt32(o);
if (iii == Num)
Numbers->Remove(o);
}
}

So did you say that i can't free unmanaged objects in managed code?
Could you please exlplain?

Thank you
Andrey
Nov 16 '05 #34

P: n/a

"MuZZy" <le*******@yahoo.com> wrote in message
news:Ro********************@comcast.com...

Ok, here is the real piece of code:

// In .h file here is the part of class declaration
public __gc class CResSet : public DataSet
{
public:
CResSet(CResSet *rs);
~CResSet();
STRMAP *m_smTables;
STRPAIRVECTOR *m_vp;
STRSET *m_ssPopulated;
<...>
}
// In .cpp file, here is the finalizer releasing unmanaged memory

// constructor
TnrData::CResSet::CResSet()
{
<..>
m_vp = new STRPAIRVECTOR();
m_ssPopulated = new STRSET(); m_smTables = new STRMAP();
<..>
}

// finalizer
TnrData::CResSet::~CResSet()
{
delete m_smTables; // THESE ARE
delete m_vp; // UNMANAGED STL
delete m_ssPopulated; // OBJECTS

Counter--;
for (int i = 0 ; i < Numbers->Count; i++)
{
Object *o = Numbers->get_Item(i);
int iii = Convert::ToInt32(o);
if (iii == Num)
Numbers->Remove(o);
}
}

So did you say that i can't free unmanaged objects in managed code?
Could you please exlplain?

Thank you
Andrey


You must be kidding, now you are talking about managed C++ wrapping
unmanaged objects.
Yes, you can destroy the objects exactly the way you are doing, but I have
some doubts about the remainder in the destructor.
Where is Num and Numbers coming from, are they members of this class?
Willy.
Nov 16 '05 #35

P: n/a
Willy Denoyette [MVP] wrote:
"MuZZy" <le*******@yahoo.com> wrote in message
news:Ro********************@comcast.com...
Ok, here is the real piece of code:

// In .h file here is the part of class declaration
public __gc class CResSet : public DataSet
{
public:
CResSet(CResSet *rs);
~CResSet();
STRMAP *m_smTables;
STRPAIRVECTOR *m_vp;
STRSET *m_ssPopulated;
<...>
}
// In .cpp file, here is the finalizer releasing unmanaged memory

// constructor
TnrData::CResSet::CResSet()
{
<..>
m_vp = new STRPAIRVECTOR();
m_ssPopulated = new STRSET(); m_smTables = new STRMAP();
<..>
}

// finalizer
TnrData::CResSet::~CResSet()
{
delete m_smTables; // THESE ARE
delete m_vp; // UNMANAGED STL
delete m_ssPopulated; // OBJECTS

Counter--;
for (int i = 0 ; i < Numbers->Count; i++)
{
Object *o = Numbers->get_Item(i);
int iii = Convert::ToInt32(o);
if (iii == Num)
Numbers->Remove(o);
}
}

So did you say that i can't free unmanaged objects in managed code?
Could you please exlplain?

Thank you
Andrey

You must be kidding, now you are talking about managed C++ wrapping
unmanaged objects.

My apology! I made a wrong assumption that in this thread we are talking mostly about managed code,
i also made a mistake originally in the sample post, didn't put __gc for class...

I'm lacking knowledge about managed c++ as i didn't have any experience with it (i had some with
regular C++ of course) up until last week.

See, the project i'm taking part in consists of 5 layers - UI is in C# and all others (like business
layer etc) are in c++. So that\s where my confusion is coming form.
Yes, you can destroy the objects exactly the way you are doing, but I have
some doubts about the remainder in the destructor.
Where is Num and Numbers coming from, are they members of this class?
Willy.


yes, "Numbers" is a static ArrayList member and Num is instance's int member

And thank you for your help!
Nov 16 '05 #36

This discussion thread is closed

Replies have been disabled for this discussion.