Delegate still calls class after set to nothing!?!

  • Thread starter Thread starter ZorpiedoMan
  • Start date Start date
Z

ZorpiedoMan

This is either a bad bug, or I'm not understanding
somthing. In my mind, this should NOT work:

------------------------------------------
Class ShouldntWork
Delegate Sub goHere()

Sub StartHere()
Dim DC as new DeadClass
Dim myDel as New goHere(AddressOf DeadClass.Here)
DC = Nothing
GC.Collect
myDel.Invoke
End Sub
End Class

Class DeadClass
Sub Here
MsgBox "How Did I Get Here?"
End Sub
End Class
--------------------------------------

I'm assuming that since a delegate is really just a
pointer to a place in memory, that invoking it still sends
us there, but isn't this dangerous? Assume that that
location on the heap has been overwritten, who knows what
will happen, right?

Comments, Please!
 
Havent used delegates much, but

Just guessing, as you instantiate a delegate myDel, the removal of the
reference DC to the delegate has no effect.

OHM#
This is either a bad bug, or I'm not understanding
somthing. In my mind, this should NOT work:

------------------------------------------
Class ShouldntWork
Delegate Sub goHere()

Sub StartHere()
Dim DC as new DeadClass
Dim myDel as New goHere(AddressOf DeadClass.Here)
DC = Nothing
GC.Collect
myDel.Invoke
End Sub
End Class

Class DeadClass
Sub Here
MsgBox "How Did I Get Here?"
End Sub
End Class
--------------------------------------

I'm assuming that since a delegate is really just a
pointer to a place in memory, that invoking it still sends
us there, but isn't this dangerous? Assume that that
location on the heap has been overwritten, who knows what
will happen, right?

Comments, Please!

Regards - OHM# (e-mail address removed)
 
That's correct, but the place in memory that is being
called should no longer be available... that's what has me
worried.
 
I think it's surely because of the Garbage Collector running in the back.

Use gc.collect after set to nothing and try again.
 
After using GC.Collect execute GC.WaitForPendinfFinalizers that will wait
until GC is done collecting..
 
ZorpiedoMan said:
This is either a bad bug, or I'm not understanding
somthing. In my mind, this should NOT work:

------------------------------------------
Class ShouldntWork
Delegate Sub goHere()

Sub StartHere()
Dim DC as new DeadClass
Dim myDel as New goHere(AddressOf DeadClass.Here)
DC = Nothing
GC.Collect
myDel.Invoke
End Sub
End Class

Class DeadClass
Sub Here
MsgBox "How Did I Get Here?"
End Sub
End Class
--------------------------------------

I'm assuming that since a delegate is really just a
pointer to a place in memory, that invoking it still sends
us there, but isn't this dangerous? Assume that that
location on the heap has been overwritten, who knows what
will happen, right?

Comments, Please!

I also think it should not work: "Here" is not a shared method, so it should
be "...addresof dc.here".

Apart from this, it _should_ work because the delegate still points to the
DC object => there is still a reference to the object => The object is not
collected.
 
Thanks, but that STILL does not answer the question as to
WHY any code executes at all??? The delegate is pointing
to UNUSED memory... there could be ANYTHING at that
point... serious potential crashing possibilities...
 
The memory space isn't completely unused just becuase you set it to nothing,
Which is why I recomended GC.WaitforpendingFinalizers because GC.Collete
runs in a different thread. it's sort of like deleting a file you delete it
but the data of the file is still on the drive..
 
Hi,

Yes, this is correct behaviour. The delegate stores a reference to both the
target and the method in the target for instance methods. This enables the
GC to move the object in memory, and still reference the same method.
See Delegate class in the framework documents for more info.
 
Bill McCarthy said:
Yes, this is correct behaviour. The delegate stores a reference to
both the target and the method in the target for instance methods.
This enables the GC to move the object in memory, and still reference
the same method. See Delegate class in the framework documents for
more info.

That's what I said. Good to know I was right. :-)
 
Yep. Shouldn't compile because the addressof should be of the instance, if
that's a typo and he's actually using the instance on the addressof
statemente, then the delegate keeps a reference to the instance - assigning
nothing to the variable DC doesn't change the object it was pointing to -
it's probably not even moved around. In any case, since the original object
still has at least one reference, the garbage collecton won't touch it.
 
ZorpiedoMan,
I'm assuming that since a delegate is really just a
pointer to a place in memory, that invoking it still sends
us there, but isn't this dangerous? Assume that that
location on the heap has been overwritten, who knows what
will happen, right?
You're assuming wrong! As Bill & Armin pointed out: A delegate is a
reference to an object along with a "reference" to a method. For shared
methods, the reference to object happens to be nothing, as obviously its not
needed.

Remember that .NET doesn't really use "a pointer to a place in memory" in
the terms of C++, instead everything is a reference that the runtime knows
about & is able to track! Via the meta data in the assembly. Yes deep under
the covers a reference is "a pointer to a place in memory", however the
important part, is the CLR runtime has a plethora of details on the pointer.

Seeing as the delegate itself still has a reference to the DeadClass object,
the DeadClass object itself will not be garbage collected. If you want the
DeadClass to really go away you will need to set the delegate to nothing
also.

One way to demonstrate this is to put a Finalizer in your DeadClass & call
WaitForPendingFinalizers.

Try single stepping the following program and watch the output window in
VS.NET

Class ShouldntWork

Delegate Sub goHere()

Public Shared Sub Main()
Dim DC As New DeadClass
Dim myDel As New goHere(AddressOf DC.Here)
DC = Nothing

Debug.WriteLine("First Collection")
GC.Collect()
GC.WaitForPendingFinalizers()

myDel.Invoke()

myDel = Nothing
Debug.WriteLine("Second Collection")
GC.Collect()
GC.WaitForPendingFinalizers()

End Sub

End Class

Class DeadClass

Public Sub Here()
Debug.WriteLine("How Did I Get Here?")
End Sub

Protected Overrides Sub Finalize()
MyBase.Finalize()
Debug.WriteLine("Finalize", "DeadClass")
End Sub

End Class

Note the change on the AddressOf statement to reference the instance method
"Here", not the non-existent Shared method "Here".

Hope this helps
Jay
 
Back
Top