Delegates appear to be weak references

M

Matthew Herrmann

Hi,

I've heard from groups that listeners to event handlers cause
references to be kept alive, if the targets are marked to stay alive. I
need to make sure that attaching events to objects will not cause them
to be kept open.

I created a test which has "target" listening to "source" for events.
After plugging source into target, I then let go of source. Since I'm
still holding onto target, if delegates were a strong reference, then
target shouldn't be collected. What I find is that it _is_ being
garbage collected, which is what I want.

If I add a normal reference to source from target, then the garbage
collection does not fire, as I expect.

Am I missing something? Why am I seeing a weak reference behaviour for
event delegates when others seem to witness strong referencing? Is this
an event vs delegate issue? Having tested this behaviour, I am about to
rely upon this in a design.

TIA,

Matthew Herrmann
Far Edge Pty Ltd
http://www.faredge.com.au/

----------------

Public Module Startup

Public Sub Main()
Dim target As New Target

Dim source As Source
source = New Source

'target.Reference = test

AddHandler source.Blah, AddressOf target.Blah
source.Fire()
MsgBox("Created")

MsgBox("Is cleaned up? " & Finalized)
source = Nothing

GC.Collect()
GC.WaitForPendingFinalizers()

MsgBox("Is cleaned up? " & Finalized)

' Test call to target, it still exists
target.Blah(Nothing, New EventArgs)

MsgBox("Finished.")
End Sub

Public Finalized As Boolean = False
End Module

Friend Class Source
Public Event Blah As EventHandler

Protected Overrides Sub Finalize()
Finalized = True
MyBase.Finalize()
End Sub

Public Sub Fire()
RaiseEvent Blah(Me, New EventArgs)
End Sub
End Class

Friend Class Target
Public Reference As Source

Public Sub Blah(ByVal sender As Object, ByVal e As EventArgs)
MsgBox("Fired!")
End Sub
End Class
 
J

Jay B. Harlow [MVP - Outlook]

Matthew,
| Am I missing something?
Yes.

| Why am I seeing a weak reference behaviour for
| event delegates when others seem to witness strong referencing?
You're not seeing weak reference behavior... As much as you are looking at
the wrong object...

| AddHandler source.Blah, AddressOf target.Blah
| source.Fire()
| source = Nothing
The source object is holding a reference to the target object. The target
object has no knowledge or reference to the source object. Hence when you
let go of the source reference the source object is free to be collected.

However! The "problem" that others are talking about is when you let go of
any explicit references to the target object, the source object still has
some implicit references to the target object, preventing the target object
from being collected.


--
Hope this helps
Jay [MVP - Outlook]
..NET Application Architect, Enthusiast, & Evangelist
T.S. Bradley - http://www.tsbradley.net


| Hi,
|
| I've heard from groups that listeners to event handlers cause
| references to be kept alive, if the targets are marked to stay alive. I
| need to make sure that attaching events to objects will not cause them
| to be kept open.
|
| I created a test which has "target" listening to "source" for events.
| After plugging source into target, I then let go of source. Since I'm
| still holding onto target, if delegates were a strong reference, then
| target shouldn't be collected. What I find is that it _is_ being
| garbage collected, which is what I want.
|
| If I add a normal reference to source from target, then the garbage
| collection does not fire, as I expect.
|
| Am I missing something? Why am I seeing a weak reference behaviour for
| event delegates when others seem to witness strong referencing? Is this
| an event vs delegate issue? Having tested this behaviour, I am about to
| rely upon this in a design.
|
| TIA,
|
| Matthew Herrmann
| Far Edge Pty Ltd
| http://www.faredge.com.au/
|
| ----------------
|
| Public Module Startup
|
| Public Sub Main()
| Dim target As New Target
|
| Dim source As Source
| source = New Source
|
| 'target.Reference = test
|
| AddHandler source.Blah, AddressOf target.Blah
| source.Fire()
| MsgBox("Created")
|
| MsgBox("Is cleaned up? " & Finalized)
| source = Nothing
|
| GC.Collect()
| GC.WaitForPendingFinalizers()
|
| MsgBox("Is cleaned up? " & Finalized)
|
| ' Test call to target, it still exists
| target.Blah(Nothing, New EventArgs)
|
| MsgBox("Finished.")
| End Sub
|
| Public Finalized As Boolean = False
| End Module
|
| Friend Class Source
| Public Event Blah As EventHandler
|
| Protected Overrides Sub Finalize()
| Finalized = True
| MyBase.Finalize()
| End Sub
|
| Public Sub Fire()
| RaiseEvent Blah(Me, New EventArgs)
| End Sub
| End Class
|
| Friend Class Target
| Public Reference As Source
|
| Public Sub Blah(ByVal sender As Object, ByVal e As EventArgs)
| MsgBox("Fired!")
| End Sub
| End Class
|
 
M

Matthew Herrmann

Thanks Jay, you're spot on. Source needs to know target, not vice
versa.

I've modified the code to test the condition and sure enough, target
does not get GC'd unless the RemoveHandler is there.

I've posted the updated code for people's future reference.


-- Matthew


--------

Public Module Startup

Public Sub Main()
Dim source As Source
source = New Source

Dim target As Target
target = New Target

AddHandler source.Blah, AddressOf target.Blah
source.Fire()

MsgBox("Created")

MsgBox("Is cleaned up? " & Finalized)

' When the following line is uncommented, target is not
' collected:
' RemoveHandler source.Blah, AddressOf target.Blah
target = Nothing

GC.Collect()
GC.WaitForPendingFinalizers()


MsgBox("Is cleaned up? " & Finalized)

MsgBox("Finished.")
End Sub

Public Finalized As Boolean = False
End Module

Friend Class Source
Public Event Blah As EventHandler

Public Sub Fire()
RaiseEvent Blah(Me, New EventArgs)
End Sub
End Class

Friend Class Target
Protected Overrides Sub Finalize()
Finalized = True
MyBase.Finalize()
End Sub

Public Sub Blah(ByVal sender As Object, ByVal e As EventArgs)
MsgBox("Fired!")
End Sub
End Class
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top