Event handler not releasing reference?

Questions about YourKit .NET Profiler
Post Reply
mike
Posts: 1
Joined: Tue Apr 28, 2009 1:34 am

Event handler not releasing reference?

Post by mike »

I've learned the hard way about event handlers in .NET, and how a long-lived event source can hold on to a reference to a short-lived event sink, thereby preventing it from being garbage-collected. For this reason, I now use weak delegates whenever possible. I use the Pvax.WeakDelegates library (http://www.codeproject.com/KB/architect ... patte.aspx).

But even with weak delegates, I've run into a case where an event handler is firing in an object that (as far as I can tell from the YourKit profiler) is not being referenced anywhere. I have reproduced the issue in a simple .NET 2.0 WinForms project in VS2005.

I have a form that contains 3 buttons. btnCreate creates an instance of a user control and adds it to the Controls collection of a panel. btnDelete calls a .Clear() method on the user control and removes it from the panel. btnChange changes the value of an application setting, defined under Properties / Settings.settings in the solution explorer. Here's the code in Form1:

Code: Select all

public partial class Form1 : Form
{
	public Form1()
	{
		InitializeComponent();
	}

	private void btnCreate_Click( object sender, EventArgs e )
	{
		if ( panel1.Controls.Count == 0 )
		{
			UserControl1 ctrl = new UserControl1();
			panel1.Controls.Add(ctrl);
		}
	}

	private void btnDelete_Click( object sender, EventArgs e )
	{
		UserControl1 ctrl = (UserControl1)panel1.Controls[0];
		ctrl.Clear();
		panel1.Controls.Clear();
	}

	private void btnChange_Click( object sender, EventArgs e )
	{
		Properties.Settings.Default.MySetting++;
	}
}
The user control (which contains a label) subscribes to the Properties.Settings.Default.PropertyChanged event by means of a weak delegate, and the handler for this event sets the label text to a string held in a member variable of type List<string>. This list is set to null by the .Clear() method when btnDelete is clicked. Here's the code in the user control:

Code: Select all

public partial class UserControl1 : UserControl
{
	private List<string> _list = new List<string>();

	public UserControl1()
	{
		InitializeComponent();
		_list.Add("foo");
		Properties.Settings.Default.PropertyChanged += 
		(PropertyChangedEventHandler)Pvax.WeakDelegates.WeakDelegateDecorator.AddHandler(
		Properties.Settings.Default, "PropertyChanged", 
		new PropertyChangedEventHandler(Settings_PropertyChanged));
	}

	public void Clear()
	{
		_list = null;
	}

	public void Settings_PropertyChanged( object sender, EventArgs e )
	{
		label1.Text = _list[0];
	}
}
At runtime, if you click btnCreate, the user control appears. If you then click btnDelete, it disappears. If you then click btnChange, you get a NullReferenceException in UserControl1's Settings_PropertyChanged event handler, because _list is null.

I have used the YourKit .NET Profiler to see what objects exist in memory after clicking each button in turn. After clicking btnCreate and taking a snapshot, the Profiler's object explorer tells me that I have an instance of Form1, an instance of Properties.Settings, and an instance of UserControl1. This is what I expect. After clicking btnDelete and taking another snapshot, the instance of UserControl1 is no longer listed in the object explorer. This is also what I expect, because nothing is referencing the user control any more.

So why does the event handler fire when I then click btnChange? The weak delegate should notice that the event sink no longer exists and silently unsubscribe from the event. I haven't had any problems with weak delegates in any other situation before.

I really can't understand what's going on in this case.
Arizona
Posts: 1
Joined: Fri Aug 07, 2009 5:49 am

Re: Event handler not releasing reference?

Post by Arizona »

Hi,

Very interested, the event handler fire when btnChange, it seem be one small bug. :shock:
Post Reply