Pls HELP!- DataSet Inherited object not finalizing

  • Thread starter Thread starter MuZZy
  • Start date Start date
M

MuZZy

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
 
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.
 
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 said:
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.
 
Nicholas said:
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
 
Willy said:
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
 
Bob said:
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

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
 
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 said:
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
 
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 said:
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]
- (e-mail address removed)


MuZZy said:
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
 
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.
 
MuZZy said:
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.
 
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.
 
Nicholas said:
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
 
Daniel said:
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!


:

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]
- (e-mail address removed)


Willy Denoyette [MVP] wrote:



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?
 
Jon said:
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...
 
Willy said:
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!
 
MuZZy said:
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.
 
Back
Top