Memory not freed if Windows Forms application uses ToolTip.SetToolTip
This article helps you resolve the problem where Windows Forms application might not release memory if using the ToolTip.SetToolTip
method incorrectly.
Original product version: .NET Framework 4.5
Original KB number: 2749543
Symptoms
You've developed a .NET Windows Forms application, which uses the ToolTip.SetToolTip
method to associate a ToolTip control with a Windows Forms control. When programmatically removing the associated Windows Forms control from the Form and Disposing of it, the control isn't released from the managed heap. Over time, if repeatedly adding and removing controls that are associated with a ToolTip
using ToolTip.SetToolTip
, memory usage continues to increase and may eventually result in a System.OutOfMemoryException
.
Cause
When calling ToolTip.SetToolTip
to associate a ToolTip
with a Windows Forms control, the ToolTip
object stores internal information, including a reference to the control, within an internal HashTable. If using a single ToolTip control and associating it with many controls, then a reference to each control and its ToolTip
information is stored within the HashTable. Neither calling a control's Dispose
method or removing it from the Controls
collection of its container disassociates the control from its ToolTip
. So in a scenario where the application is adding controls dynamically to a Form, associating them with a ToolTip
, and removing and disposing of them; the control is still rooted in memory and the application's managed memory heap will continue to grow over time.
Resolution
Depending on the application design, there are several ways to resolve this problem.
If the application is using one ToolTip control for many Windows Forms controls, then you can disassociate a particular Windows Forms control from the ToolTip by calling ToolTip.SetToolTip
and passing a reference to the control and an empty string for the ToolTip
caption. When an empty string is passed for the ToolTip
caption, the SetToolTip
method removes the reference to the Windows Forms control from within the internal HashTable of ToolTip
.
Note
You can also call the ToolTip.RemoveAll
to remove all ToolTip
text and disassociate the ToolTip control from all Windows Forms controls.
If the application isn't associating multiple Windows Forms controls with a single ToolTip, then you can call the Dispose
method of ToolTip
.
More information
This behavior is by design.
Consider the following sample code in a Windows Forms application. The code in the CreateControls()
method creates a number of TextBox controls, calls ToolTip.SetToolTip
to assign a ToolTip
caption to each Control, and adds the control to an internal ObservableCollection
, and to the Controls
collection. The code in the RemoveControls()
method walks over the ObservableCollection
, gets a reference to each control, and then removes it from the ObservableCollection
and the Form's Controls
collection, and then calls its Dispose
method. It results in each of the TextBox controls being removed from the Form and disposed, but the instance of each TextBox and associated ToolTipInfo
are still rooted in the managed heap. Uncommenting the specified line in the RemoveControls()
method disassociates the TextBox from the ToolTip
and allows it to be garbage collected.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Collections.ObjectModel;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
ObservableCollection<TextBox> list;
ToolTip toolTip;
public Form1()
{
InitializeComponent();
toolTip = new ToolTip();
list = new ObservableCollection<TextBox>();
}
private void button1_Click(object sender, EventArgs e)
{
CreateControls();
}
private void button2_Click(object sender, EventArgs e)
{
RemoveControls();
}
private void CreateControls()
{
for (int i = 0; i < 100; i++)
{
TextBox t = new TextBox();
toolTip.SetToolTip(t, i.ToString());
t.Left = (t.Width * i) + 5;
list.Add(t);
this.Controls.Add(t);
}
}
private void RemoveControls()
{
for (int i = list.Count-1;i>=0;i--)
{
TextBox tb = list[i];
this.Controls.Remove(tb);
list.Remove(tb);
//Uncomment this line to disassociate the ToolTip control from the Windows Forms Control
//toolTip.SetToolTip(tb, "");
tb.Dispose();
}
}
}
}