Microsoft KB Archive/813137

= BUG: A memory leak occurs when you use data binding in Windows Forms =

PSS ID Number: 813137

Article Last Modified on 5/24/2005

-

The information in this article applies to:


 * Microsoft Visual Studio .NET (2002), Professional Edition
 * Microsoft Visual Studio .NET (2002), Enterprise Architect Edition
 * Microsoft Visual Studio .NET (2002), Enterprise Developer Edition
 * Microsoft Visual Studio .NET (2002), Academic Edition

-





SYMPTOMS
A memory leak occurs in Microsoft Windows Forms that use data binding. Any data-bound control leaks an instance of the object that it is bound to when the control is destroyed. After time, the Windows Form application grows unresponsive.



CAUSE
This problem occurs because the Dispose function of the control does not clear the DataBindings collection. Unless you take explicit coding steps to work around this problem, it will affect every application that uses Windows Forms and data binding.



WORKAROUND
To work around this problem, use one of the following methods:
 * 1) Derive all controls, and make sure that each control clears its data binding collection in its own Dispose method.
 * 2) Make sure that all forms clear the data binding collections of their child controls when the form is disposed.

Generally, the following code can work around this kind of issue in any other forms: void ClearChildBindings( Control c ) {       if (!c.IsDisposed) {           c.DataBindings.Clear;

foreach (Control child in c.Controls) {               ClearChildBindings(child); }       }    }

void Dispose( bool disposing ) {       if (disposing) {           ClearChildBindings(this); }   }



STATUS
Microsoft has confirmed that this is a bug in the Microsoft products that are listed in the &quot;Applies to&quot; section.



Steps to reproduce the behavior
 Start Microsoft Visual Studio .NET. On the File menu, point to New, and then click Project. Under Project Types, click Visual C# Projects, and then click Windows Application under Templates. Type Q813137 in Name box, and then click OK. By default, a form that is named Form1 is created. In Solution Explorer, right-click Form1.cs, and then click View Code.</li>  Replace the code in Form1.cs with the following code: using System; using System.Drawing; using System.Collections; using System.ComponentModel; using System.Windows.Forms; using System.Data;

namespace Q813137 {   ///     /// Summary description for Form1. ///    public class Form1 : System.Windows.Forms.Form {       private System.Windows.Forms.Button button1; ///        /// Required designer variable. ///        private System.ComponentModel.Container components = null;

public Form1 {           //            // Required for Windows Form Designer support //           InitializeComponent;

}

///        /// Clean up any resources being used. ///        protected override void Dispose( bool disposing ) {           if( disposing ) {               if (components != null) {                   components.Dispose; }           }            base.Dispose( disposing ); }

#region Windows Form Designer generated code ///        /// Required method for Designer support - do not modify /// the contents of this method with the code editor. ///        private void InitializeComponent {           this.button1 = new System.Windows.Forms.Button; this.SuspendLayout; //            // button1 //            this.button1.Location = new System.Drawing.Point(16, 16); this.button1.Name = &quot;button1&quot;; this.button1.Size = new System.Drawing.Size(160, 48); this.button1.TabIndex = 0; this.button1.Text = &quot;Start&quot;; this.button1.Click += new System.EventHandler(this.button1_Click); //            // Form1 //            this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); this.ClientSize = new System.Drawing.Size(192, 78); this.Controls.AddRange(new System.Windows.Forms.Control[] {                                                                         this.button1}); this.Name = &quot;Form1&quot;; this.Text = &quot;Form1&quot;; this.ResumeLayout(false);

}       #endregion

///        /// The main entry point for the application. ///        [STAThread] static void Main {           Application.Run(new Form1); }

private void button1_Click(object sender, System.EventArgs e)       { for (int i = 0; i < 100; i++) {               Form2 f = new Form2; f.Show; f.Hide; f.Dispose; }           System.GC.Collect; System.GC.WaitForPendingFinalizers; System.GC.Collect; }   } } </li> Right-click Q813137 in Solution Explorer, point to Add, and then click Add New Item.</li> In the Add New Item dialog box, click Windows Form under Templates, and then click OK. By default, the form that is named Form2 is added to the project.</li> In Solution Explorer, right-click Form2.cs, and then click View Code.</li>  Replace the code in Form2.cs with the following code: using System; using System.Drawing; using System.Collections; using System.ComponentModel; using System.Windows.Forms;

namespace Q813137 {   ///     /// Summary description for Form2. ///    public class Form2 : System.Windows.Forms.Form {       private System.Windows.Forms.TextBox textBox1; ///        /// Required designer variable. ///        private System.ComponentModel.Container components = null;

public Form2 {           //            // Required for Windows Form Designer support //           InitializeComponent;

DataClass dc = new DataClass(&quot;ABC&quot;);

// Comment out this line and private bytes stops growing. // Leave this line in and we seem to grow private bytes. textBox1.DataBindings.Add(&quot;Text&quot;, dc, &quot;S&quot;); }

///        /// Clean up any resources being used. ///

//TODO: Workaround step 1: Comment the following Dispose function. protected override void Dispose( bool disposing ) {           if( disposing ) {               if(components != null) {                   components.Dispose; }           }            base.Dispose( disposing ); }       //TODO; Workaround step 2: Uncomment the following ClearChildBindings and Dispose functions. /*void ClearChildBindings(Control c)       { if (!c.IsDisposed) {               c.DataBindings.Clear;

foreach (Control child in c.Controls) {                   ClearChildBindings(child); }           }        }

protected override void Dispose( bool disposing ) {           if (disposing) {               ClearChildBindings(this); }       }*/        #region Windows Form Designer generated code ///        /// Required method for Designer support - do not modify /// the contents of this method with the code editor. ///        private void InitializeComponent {           this.textBox1 = new System.Windows.Forms.TextBox; this.SuspendLayout; //            // textBox1 //            this.textBox1.Location = new System.Drawing.Point(32, 24); this.textBox1.Name = &quot;textBox1&quot;; this.textBox1.Size = new System.Drawing.Size(232, 20); this.textBox1.TabIndex = 0; this.textBox1.Text = &quot;textBox1&quot;; //            // Form2 //            this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); this.ClientSize = new System.Drawing.Size(292, 70); this.Controls.AddRange(new System.Windows.Forms.Control[] {                                                                         this.textBox1}); this.Name = &quot;Form2&quot;; this.Text = &quot;Form2&quot;; this.ResumeLayout(false);

}       #endregion }

public class DataClass {       public DataClass(string s)        { _s = s;           _b = new byte[65536]; }       public string S        { get {               return(_s); }           set {               _s = value; }       }        private string _s; private byte[] _b; } } </li> Press F5 to build and run the program.</li></ol>

Test the sample
<ol> In Control Panel, double-click Administrative Tools, and then double-click Performance.</li> In the Performance MMC add-in, you can use the #Bytes in all Heaps counter in the .NET CLR Memory performance object to monitor Q813137. To do this, follow these steps: <ol style="list-style-type: lower-alpha;"> Right-click the view graphic section, and then click Add Counters.</li> Click .NET CLR Memory in the Performance object list, and then click #Bytes in all Heaps in the Select counters from list section.</li> Click Add, and then click Close.</li></ol> </li> In Form1 (Q813137), click Start.</li></ol>

Result:

You find the memory that is used by Q813137 increases quickly in the Performance MMC add-in.

Workaround for the sample in the More Information Section

 * 1) In Visual Studio .NET, search TODO in the Form2.cs.
 * 2) Modify code where you see TODO.
 * 3) Press F5 to build and run the program.
 * 4) Run the steps in the &quot;Test the Sample&quot; section again.

Result

You find the memory that is used by Q813137 keeps stable in the Performance MMC add-in.

Keywords: kbControl kbForms kbBug KB813137

Technology: kbAudDeveloper kbVSNET2002Ac kbVSNET2002EntArch kbVSNET2002EntDev kbVSNET2002Pro kbVSNET2002Search kbVSNETSearch kbVSsearch

-

[mailto:TECHNET@MICROSOFT.COM Send feedback to Microsoft]

© Microsoft Corporation. All rights reserved.