Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / .NET Framework / CLR / November 2003

Tip: Looking for answers? Try searching our database.

Object state after finalization (was InvalidOperationException from invalid GCHandle in WeakReference)

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Niall - 10 Nov 2003 23:52 GMT
This is related to my previous post about getting an
InvalidOperationException from a WeakReference. Since my original post,
another programmer has created a situation where this is happening. However,
it is happening at shutdown where all the finalizers are being run. I do not
think this person's code is correct, I think it's doing things in a
Finalizer that it shouldn't be.

I know that at shutdown time, objects will be finalized (in general, at
least.. it seems as though you can't rely on them being finalized). And I
know that finalization can occur in any order, which is why you can't rely
on an object's references when you are running that object's finalizer. What
I think is happening in this case is that this object's WeakReference is
being finalized before the object itself is. When the object's finalizer
does its thing, the WeakReference gives the exception. However, there isn't
a NullReferenceException, it's an exception from the internals of the
WeakReference.

So this makes it appear to me that the WeakReference object is still alive.
It has been finalized, and is now waiting in the heap for the next run of
the GC, whereupon it will be identified as garbage and removed. I know that
at shutdown, there won't be another GC, but I think this may be the same
situation as I found myself in previously, which was during runtime, before
shutdown.

So am I right in assuming that if we catch the WeakReference after
finalization but before the GC removes it, it will be in this state? I guess
the only way you could access a WeakReference in this state (short of
resurrection situations) would be from another object's finalizer. I say
this because if it was from normal code in another object, then there would
be a root path to the WeakReference, and it wouldn't have been finalized in
the first place.

I think the problematic code in this case needs a refactor such that
whatever work it is doing is done either in a Dispose method or in something
else deterministic and under our control, rather than using a finalizer to
catch when an object is no longer used because we haven't designed well
enough to know that from our own code.

Niall
Niall - 11 Nov 2003 01:14 GMT
Further to this question, I have the following request for clarification,
which I think is best asked through an example.

Let's say we have three objects - A, B and C. A refers to B, and B refers to
C (ie A -> B -> C). A and C have finalizers, but B does not. Let's say that
nothing is referencing A, and the GC kicks in.

All three objects are garbage, and A and C need to be finalized. So A and C
get shifted off to the freachable queue, and there are now roots to both
objects. So my first question is: seeing as A referenced B, and there is now
a root to A, will B now be upgraded from garbage to living? Or will it be
collected?

If B remains alive, waiting for A's final collection, what happens if A's
finalizer calls some cleanup method (perhaps Dispose) on B? B has no way of
knowing that C might have already been finalized. So there is the
possibility that this cleanup method might have problems. From a design
point of view, what's the correct behaviour here? Should finalizers not call
cleanup methods on other objects? Or should cleanup methods deal with the
possibility that the objects they use may have been finalized?

I hope my post is clear enough for other people to understand. Thinking
about this stuff is twisting knots inside my head.

Niall
Jon Skeet [C# MVP] - 11 Nov 2003 08:39 GMT
> Further to this question, I have the following request for clarification,
> which I think is best asked through an example.
[quoted text clipped - 8 lines]
> a root to A, will B now be upgraded from garbage to living? Or will it be
> collected?

I don't believe B is truly marked as garbage in the first place. It
will be alive until A and C are marked as garbage rather than just
freachable.

> If B remains alive, waiting for A's final collection, what happens if A's
> finalizer calls some cleanup method (perhaps Dispose) on B? B has no way of
[quoted text clipped - 3 lines]
> cleanup methods on other objects? Or should cleanup methods deal with the
> possibility that the objects they use may have been finalized?

It should always be safe to call Dispose on an object which implements
IDisposable, even if it's already been disposed - your implementation
of Dispose should make sure of that.

Signature

Jon Skeet - <skeet@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too

Niall - 13 Nov 2003 02:22 GMT
inline

> I don't believe B is truly marked as garbage in the first place. It
> will be alive until A and C are marked as garbage rather than just
> freachable.

Hmm, you could be right. I was basing my understanding from those two
consecutive MSDN articles on the GC, where it says:

"You'll notice in the previous section that when an application is no longer
accessing a live object, the garbage collector considers the object to be
dead. However, if the object requires finalization, the object is considered
live again until it is actually finalized, and then it is permanently dead.
In other words, an object requiring finalization dies, lives, and then dies
again. This is a very interesting phenomenon called resurrection.
Resurrection, as its name implies, allows an object to come back from the
dead." - http://msdn.microsoft.com/msdnmag/issues/1100/gci/

However, it could well have been a simplification, and also that article is
quite old now (I think it is from the end of 2001). It would make sense to
me if the GC did work as you say.

> > If B remains alive, waiting for A's final collection, what happens if A's
> > finalizer calls some cleanup method (perhaps Dispose) on B? B has no way of
[quoted text clipped - 7 lines]
> IDisposable, even if it's already been disposed - your implementation
> of Dispose should make sure of that.

Sorry, I wasn't referring to re-disposing a control that's already been
disposed. I was referring to, when finalizing, calling Dispose() on a
Control, which will call its Dispose(bool disposing) method with disposing =
true. I was wondering if it's bad to call Dispose in such a way where the
Control thinks it's not being finalized, but where, in reality, everything
of the form it was on is being finalized around it.

Basically what I mean is, is either one of the following bad code for some
reason:

~SomeClass()
{
   SomeOtherControl.Dispose();
   base.Finalize();
}

or, in SomeClass:

protected override Dispose(bool disposing)
{
   if (disposing)
   {
       ...
   }
   SomeOtherControl.Dispose();
   ...
   base.Dispose(disposing);
}

Hope this makes some sense,

Niall
Jon Skeet [C# MVP] - 13 Nov 2003 07:23 GMT
> Basically what I mean is, is either one of the following bad code for some
> reason:
[quoted text clipped - 19 lines]
>
> Hope this makes some sense,

I don't think either is particularly bad, no. Of course, if you don't
call dispose there then the finalizer will get it next time the GC
collects that generation anyway - and you're already in the case where
someone has failed to call Dispose properly if this is coming up.

Signature

Jon Skeet - <skeet@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too

Sebastien Lambla - 11 Nov 2003 15:20 GMT
You should implement IDisposable on both A, B and C. In the Dispose(bool)
prototype, just make sure you call the Dispose on all direct child objects,
and that you do call GC.SuppressFinalize().

But, frankly, there are very few cases where it's a good idea to use the
Finalizer for anything. Especially if you're using a WeakReference. Unless
you hold OS resources!

I'm afraid I don't have enough background on the whole story before knowing
what to say

Signature

Sebastien Lambla
http://thetechnologist.is-a-geek.com/blog/

> Further to this question, I have the following request for clarification,
> which I think is best asked through an example.
[quoted text clipped - 21 lines]
>
> Niall
Niall - 13 Nov 2003 04:37 GMT
In this particular case, the object with the finalizer is hooking itself up
to some internal classes that manage local machine data concurrency issues
(ie two separate forms in the application both open, one affecting the
other's data). It's supposed to be transparent from the programmers here, so
that it doesn't need any extra hands on work. So the reason for not doing it
with a dispose is that there is no apparent reason for anyone using the
class to suspect it would need disposing, and I think in a lot of cases,
people would forget to call the dispose, or be confused as to why it's
there.

The other trouble is that it seems the exact lifetime of this object is not
controlled by any one other object - ie: No one place in the code in the
system could definitively say "Ok, this object is now finished with" and
call dispose. This is because the object can potentially be shared between
different forms, etc. Personally, I think a situation where nobody knows
when an object has finished its purpose is indicative of a hole in the
design somewhere. But I haven't been able to come up with a better idea to
propose to the person who wrote it, and they're not exactly open minded
about the potential for design flaws in *their* code :P

Niall

> You should implement IDisposable on both A, B and C. In the Dispose(bool)
> prototype, just make sure you call the Dispose on all direct child objects,
[quoted text clipped - 38 lines]
> >
> > Niall
Jon Skeet [C# MVP] - 13 Nov 2003 07:25 GMT
> The other trouble is that it seems the exact lifetime of this object is not
> controlled by any one other object - ie: No one place in the code in the
[quoted text clipped - 5 lines]
> propose to the person who wrote it, and they're not exactly open minded
> about the potential for design flaws in *their* code :P

My feeling is the same as yours. Personally I'd work out a sort of
reference counting system for this - have a proxy object which controls
the lifetime, and each owner has to declare its ownership and then
release it, and if the count then goes down to zero, the proxy calls
Dispose.

That has all the normal inherent problems of reference counting, of
course - in particular if two of these objects can "own" each other -
but for many cases it should work fine.

Signature

Jon Skeet - <skeet@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too

Sebastien Lambla - 13 Nov 2003 11:15 GMT
Proxying and ref counting is doable under .net, but it has it's share of
problems as you mentionned.

As to knowing when an object is or is not garbage collected, holding a short
WeakRef on an object, and not disposing the WeakRef whatever happens is the
best way to track that. I repeat it, but using the IDisposable pattern is
the best way to handle finalization, finalizer in c# should only rely on
your dispose method if you do so

Signature

Sebastien Lambla
http://thetechnologist.is-a-geek.com/blog/

> > The other trouble is that it seems the exact lifetime of this object is not
> > controlled by any one other object - ie: No one place in the code in the
[quoted text clipped - 15 lines]
> course - in particular if two of these objects can "own" each other -
> but for many cases it should work fine.

Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.