Why not destructor?

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

I have heard that if I add a constructor it is not good, it complicates
things and that it is better to use the Dispose.
Can anybody explain this for me?
 
Sharon said:
I have heard that if I add a constructor it is not good, it complicates
things and that it is better to use the Dispose.
Can anybody explain this for me?

I believe you mean destructor, not constructor.

Finalizers (which are what you actually get) aren't called
deterministically - they're called when the GC gets round to it. This
could be much later than you really want, and indeed it may never
happen at all. That's a really bad situation to be in if you need to
free up resources so that something else can use them.

Finalizers also take longer to free up, as the GC has to notice that
nothing is referencing the object, run the finalizer, and then actually
reclaim the memory the following time it runs.
 
There are various problems with the C# 'destructor'.

First, you never know when or if it will be called. So it's not like a C++
destructor, where it gets called the moment the object goes out of scope or
is deleted. It won't be called until a garbage collect occurs. If your
system is not busy right now it could literally be hours before the
destructor runs, even though the object is out of use.

When your application exits, .NET tries to run all finalizers (C#
destructors are really finalizers in disguise), but if it takes more than a
few seconds, it just gives up. So you can never be sure the destructor will
run.

Also, you can't use other finalizable objects from within your destructor.
(I.e. other objects that have destructors.) This is because .NET makes no
guarantees about the order in which it runs finalizers. So it's quite
possible that any objects you were using have already been finalized by the
time your destructor runs. Calling methods on an object whose destructor
has already been run is never a good idea. And since you can't be sure
which ones have been finalized (or indeed which of the objects you are using
even have a finalizer) it's not safe to use objects.

So all of that means that destructors aren't actually a great deal of use.
The main reason for implementing a finalizer is because your object wraps
some kind of raw handle (e.g. a raw Win32 handle, or maybe a handle obtained
through Interop from some unmanaged library) and you need to ensure that it
gets freed. But this is just a safety net, and not a terribly reliable one,
given the limitations mentioned above.


Worse, finalizers cause performance issues. The system has to work harder
to track finalizable objects. Try writing a loop to see how fast you can
create objects without destructors and how fast you can create objects with
destructors - something like this:

int cout = 0;
while (true)
{
new MyClass();
count += 1;
if (count % 10000000 == 0) Console.WriteLine(count);
}

If MyClass does not have a destructor, it creates about 20 million objects a
second on my system. If it does have a destructor, it only manages about 2
million!

Also, finalizers cause objects to hang around in memory very much longer
than they otherwise would, which increases the working set of the process.

So they are best avoided.
 
Sharon said:
I have heard that if I add a constructor it is not good, it complicates
things and that it is better to use the Dispose.
Can anybody explain this for me?

Constructor is fine (your message). The problem with destructors (your
subject) is that in .NET you don't know when they will execute, since
objects aren't destroyed when they go out of scope, but when the garbage
collector cleans then up. The Dispose pattern gives you guaranteed execution
when Dispose is called.

Tim
..NET pros and cons
http://www.itwriting.com/phorum/list.php?f=6
 
Jon said:
Finalizers (which are what you actually get) aren't called
deterministically - they're called when the GC gets round to it.
This could be much later than you really want,
and indeed it may never happen at all.
In what scenarios do the finalizer get omitted?
Finalizers also take longer to free up, as the GC has to notice that
nothing is referencing the object, run the finalizer, and then actually
reclaim the memory the following time it runs.
I always define a destructor for my classes.
Is that bad?
If i would not do that, then System.Object::Finalize
would provide the destructor and it would run anyway, would it not?
I thought the destructor was an overridden method from System.Object,
and if it was not overridden, then the System.Object::Finalize(or higher
base class with Finalize overriden) was called.
 
Great post Ian,

I would just want to add that if you really need a destructor you should
make a rule of implementing the IDisposible interface as well.

While it doesn't take care of the perf issue Ian mentions, it gives the
user of your class a chance to release the external resources before
they remove the root reference to the object. Additionally we could turn
the finalizer off for our object when we know that the dispose method
has been called.

In thoose scenarios I usally conform to the following:

private void Dispose(bool disposing)
{
// release stuff

if ( disposing )
GC.SupressFinilize(this);
}

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

~MyClass()
{
this.Dispose(false);
}
 
If you put GC.SuppressFinalize in your Dispose, and Dispose is called, it does stop the performance issues with finallizers as the GC will not put the object on the finalization queue (and so promote it to Gen1 in the process)

Regards

Richard Blewett - DevelopMentor
http://www.dotnetconsult.co.uk/weblog
http://www.dotnetconsult.co.uk

Great post Ian,

I would just want to add that if you really need a destructor you should
make a rule of implementing the IDisposible interface as well.

While it doesn't take care of the perf issue Ian mentions, it gives the
user of your class a chance to release the external resources before
they remove the root reference to the object. Additionally we could turn
the finalizer off for our object when we know that the dispose method
has been called.
 
The GC only puts the object on the finalization queue if it's class *overrides* Finalize, or its base class other than System.Object has overridden Finalize. So if you omit it no finalization takes place. So *never* override finalize (implement a destructor) unless you really need it - in other words only if you've got hold of an unmanaged resource via interop that needs freeing should you provide a destructor.

Regards

Richard Blewett - DevelopMentor
http://www.dotnetconsult.co.uk/weblog
http://www.dotnetconsult.co.uk

I always define a destructor for my classes.
Is that bad?
If i would not do that, then System.Object::Finalize
would provide the destructor and it would run anyway, would it not?
I thought the destructor was an overridden method from System.Object,
and if it was not overridden, then the System.Object::Finalize(or higher
base class with Finalize overriden) was called.
 
Dennis Myrén said:
I always define a destructor for my classes.
Is that bad?

Yes. It means your objects will always survive on the managed heap for far
longer than is necessary. And by extension, so will any objects that your
objects refer to.

If i would not do that, then System.Object::Finalize
would provide the destructor and it would run anyway, would it not?

Actually no. If you don't override the Finalize method, the CLR never calls
it. It knows that System.Object doesn't do anything in its Finalize method,
so it doesn't call it. The only reason Object has a a Finalize method is so
that you can override it.

I thought the destructor was an overridden method from
System.Object, and if it was not overridden, then the
System.Object::Finalize(or higher base class with
Finalize overriden) was called.

Yes it is an overridden method, but no, if it's not overridden then the CLR
knows it doesn't have to call it.
 
Dennis Myrén said:
In what scenarios do the finalizer get omitted?

If finalization of all objects is taking too long when a process ends.
I always define a destructor for my classes.
Is that bad?
Yes.

If i would not do that, then System.Object::Finalize
would provide the destructor and it would run anyway, would it not?
I thought the destructor was an overridden method from System.Object,
and if it was not overridden, then the System.Object::Finalize(or higher
base class with Finalize overriden) was called.

object.Finalize doesn't do anything, and the CLR knows this - so it
only puts things which override Finalize onto the finalization queue.
 
Well yes, from the moment of the Dispose call and forward. But not the
perf issue when creating and maintaining the object before the dispose
method is called.
 
Are you talking about the impact during creation as the runtime puts a reference to the object on the finalizable list? Yes, that is there, but apart from this, there is no overhead in "maintaining" the object as far as I'm aware.

I'm assume you are referring to Chris Brumme's take on this or something similar

http://blogs.msdn.com/cbrumme/archive/2004/02/20/77460.aspx

Regards

Richard Blewett - DevelopMentor
http://www.dotnetconsult.co.uk/weblog
http://www.dotnetconsult.co.uk

nntp://news.microsoft.com/microsoft.public.dotnet.languages.csharp/<[email protected]>

Well yes, from the moment of the Dispose call and forward. But not the
perf issue when creating and maintaining the object before the dispose
method is called.
 
Back
Top