Since my support request has gone unanswered since it was entered last wednesday, I thought I would try the forum and see if anyone else has seen this issue.
I am binding a business object to a ultracombo and the objects are not being released when the business object has a collection property of type ICollection<>.
If the type is changed from an ICollection<> to a Collection<>, the objects are properly disposed.
If I bind the entity to a System.Windows.Forms.ComboBox, the objects are properly disposed.
Steps to repoduce:
1) Run the following sample code in a memory profiler (We are using ANTS from Redgate).
2) After the application is running, use a memory profiler and notice that there are 5000 Employee objects still in memory even though only one of them is still bound to the control.
3) Modify the code to bind to the System.Windows.Forms.ComboBox and rerun that application. This time there is only 1 object in memory.
4) Instead of step 3 modify the code to to use Collection<> instead of ICollection<> and rerun that application. This time there is again only 1 object in memory.
So the problem appears to be with the Infragistics control. I supect this may also be a problem with the UltraGrid control. This is a high priority issue for us because our application is auto-refreshing changes and over long periods of time significant memory is used up.
FORM CODE:
using System;using System.Collections.Generic;using System.Collections.ObjectModel;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows.Forms;Designer CODE:
namespace InterfaceBindingMemoryLeak{ public partial class Form1 : Form { public Form1() { InitializeComponent(); }
protected override void OnLoad(EventArgs e) { base.OnLoad(e);
for (int iLoop = 0; iLoop < 5000; iLoop++) { Employee[] plans = new Employee[1]; plans[0] = new Employee(); plans[0].Version = "2009-Q2";
ultraCombo1.SetDataBinding(plans, "", true); //comboBox1.DataSource = plans; } } }
public class Employee {
#region [ Constructors ]
public Employee() {
}
#endregion [ Constructors ]
#region [ Public Properties ]
public virtual string Version { get; set; }
//public virtual Collection<Locations> Deliverables public virtual ICollection<Locations> Deliverables { get { return null; } }
#endregion [ Public Properties ] }
public class Locations { public string address { get; set; } }}
DESIGNER CODE:
namespace InterfaceBindingMemoryLeak{ partial class Form1 { /// <summary> /// Required designer variable. /// </summary> private System.ComponentModel.IContainer components = null;
/// <summary> /// Clean up any resources being used. /// </summary> /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); }
#region Windows Form Designer generated code
/// <summary> /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// </summary> private void InitializeComponent() { Infragistics.Win.Appearance appearance4 = new Infragistics.Win.Appearance(); Infragistics.Win.Appearance appearance1 = new Infragistics.Win.Appearance(); Infragistics.Win.Appearance appearance2 = new Infragistics.Win.Appearance(); Infragistics.Win.Appearance appearance3 = new Infragistics.Win.Appearance(); Infragistics.Win.Appearance appearance12 = new Infragistics.Win.Appearance(); Infragistics.Win.Appearance appearance7 = new Infragistics.Win.Appearance(); Infragistics.Win.Appearance appearance6 = new Infragistics.Win.Appearance(); Infragistics.Win.Appearance appearance5 = new Infragistics.Win.Appearance(); Infragistics.Win.Appearance appearance9 = new Infragistics.Win.Appearance(); Infragistics.Win.Appearance appearance11 = new Infragistics.Win.Appearance(); Infragistics.Win.Appearance appearance10 = new Infragistics.Win.Appearance(); Infragistics.Win.Appearance appearance8 = new Infragistics.Win.Appearance(); this.comboBox1 = new System.Windows.Forms.ComboBox(); this.ultraCombo1 = new Infragistics.Win.UltraWinGrid.UltraCombo(); ((System.ComponentModel.ISupportInitialize)(this.ultraCombo1)).BeginInit(); this.SuspendLayout(); // // comboBox1 // this.comboBox1.FormattingEnabled = true; this.comboBox1.Location = new System.Drawing.Point(242, 12); this.comboBox1.Name = "comboBox1"; this.comboBox1.Size = new System.Drawing.Size(121, 21); this.comboBox1.TabIndex = 5; // // ultraCombo1 // this.ultraCombo1.CheckedListSettings.CheckStateMember = ""; appearance4.BackColor = System.Drawing.SystemColors.Window; appearance4.BorderColor = System.Drawing.SystemColors.InactiveCaption; this.ultraCombo1.DisplayLayout.Appearance = appearance4; this.ultraCombo1.DisplayLayout.BorderStyle = Infragistics.Win.UIElementBorderStyle.Solid; this.ultraCombo1.DisplayLayout.CaptionVisible = Infragistics.Win.DefaultableBoolean.False; appearance1.BackColor = System.Drawing.SystemColors.ActiveBorder; appearance1.BackColor2 = System.Drawing.SystemColors.ControlDark; appearance1.BackGradientStyle = Infragistics.Win.GradientStyle.Vertical; appearance1.BorderColor = System.Drawing.SystemColors.Window; this.ultraCombo1.DisplayLayout.GroupByBox.Appearance = appearance1; appearance2.ForeColor = System.Drawing.SystemColors.GrayText; this.ultraCombo1.DisplayLayout.GroupByBox.BandLabelAppearance = appearance2; this.ultraCombo1.DisplayLayout.GroupByBox.BorderStyle = Infragistics.Win.UIElementBorderStyle.Solid; appearance3.BackColor = System.Drawing.SystemColors.ControlLightLight; appearance3.BackColor2 = System.Drawing.SystemColors.Control; appearance3.BackGradientStyle = Infragistics.Win.GradientStyle.Horizontal; appearance3.ForeColor = System.Drawing.SystemColors.GrayText; this.ultraCombo1.DisplayLayout.GroupByBox.PromptAppearance = appearance3; this.ultraCombo1.DisplayLayout.MaxColScrollRegions = 1; this.ultraCombo1.DisplayLayout.MaxRowScrollRegions = 1; appearance12.BackColor = System.Drawing.SystemColors.Window; appearance12.ForeColor = System.Drawing.SystemColors.ControlText; this.ultraCombo1.DisplayLayout.Override.ActiveCellAppearance = appearance12; appearance7.BackColor = System.Drawing.SystemColors.Highlight; appearance7.ForeColor = System.Drawing.SystemColors.HighlightText; this.ultraCombo1.DisplayLayout.Override.ActiveRowAppearance = appearance7; this.ultraCombo1.DisplayLayout.Override.BorderStyleCell = Infragistics.Win.UIElementBorderStyle.Dotted; this.ultraCombo1.DisplayLayout.Override.BorderStyleRow = Infragistics.Win.UIElementBorderStyle.Dotted; appearance6.BackColor = System.Drawing.SystemColors.Window; this.ultraCombo1.DisplayLayout.Override.CardAreaAppearance = appearance6; appearance5.BorderColor = System.Drawing.Color.Silver; appearance5.TextTrimming = Infragistics.Win.TextTrimming.EllipsisCharacter; this.ultraCombo1.DisplayLayout.Override.CellAppearance = appearance5; this.ultraCombo1.DisplayLayout.Override.CellClickAction = Infragistics.Win.UltraWinGrid.CellClickAction.EditAndSelectText; this.ultraCombo1.DisplayLayout.Override.CellPadding = 0; appearance9.BackColor = System.Drawing.SystemColors.Control; appearance9.BackColor2 = System.Drawing.SystemColors.ControlDark; appearance9.BackGradientAlignment = Infragistics.Win.GradientAlignment.Element; appearance9.BackGradientStyle = Infragistics.Win.GradientStyle.Horizontal; appearance9.BorderColor = System.Drawing.SystemColors.Window; this.ultraCombo1.DisplayLayout.Override.GroupByRowAppearance = appearance9; appearance11.TextHAlignAsString = "Left"; this.ultraCombo1.DisplayLayout.Override.HeaderAppearance = appearance11; this.ultraCombo1.DisplayLayout.Override.HeaderClickAction = Infragistics.Win.UltraWinGrid.HeaderClickAction.SortMulti; this.ultraCombo1.DisplayLayout.Override.HeaderStyle = Infragistics.Win.HeaderStyle.WindowsXPCommand; appearance10.BackColor = System.Drawing.SystemColors.Window; appearance10.BorderColor = System.Drawing.Color.Silver; this.ultraCombo1.DisplayLayout.Override.RowAppearance = appearance10; this.ultraCombo1.DisplayLayout.Override.RowSelectors = Infragistics.Win.DefaultableBoolean.False; appearance8.BackColor = System.Drawing.SystemColors.ControlLight; this.ultraCombo1.DisplayLayout.Override.TemplateAddRowAppearance = appearance8; this.ultraCombo1.DisplayLayout.ScrollBounds = Infragistics.Win.UltraWinGrid.ScrollBounds.ScrollToFill; this.ultraCombo1.DisplayLayout.ScrollStyle = Infragistics.Win.UltraWinGrid.ScrollStyle.Immediate; this.ultraCombo1.DisplayLayout.ViewStyleBand = Infragistics.Win.UltraWinGrid.ViewStyleBand.OutlookGroupBy; this.ultraCombo1.Location = new System.Drawing.Point(13, 12); this.ultraCombo1.Name = "ultraCombo1"; this.ultraCombo1.Size = new System.Drawing.Size(100, 22); this.ultraCombo1.TabIndex = 6; this.ultraCombo1.Text = "ultraCombo1"; // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(459, 143); this.Controls.Add(this.ultraCombo1); this.Controls.Add(this.comboBox1); this.Name = "Form1"; this.Text = "Form1"; ((System.ComponentModel.ISupportInitialize)(this.ultraCombo1)).EndInit(); this.ResumeLayout(false); this.PerformLayout();
#endregion
private System.Windows.Forms.ComboBox comboBox1; private Infragistics.Win.UltraWinGrid.UltraCombo ultraCombo1; }}
Hi,
I'm not entirely sure exactly why using IList instead of List causes a memory leak, but I can tell you that using an IList for data binding is not a good practice. This will results in all sorts of odd behaviors and problems. In fact, even using List<T> is not the best practice, because List<T> does not provide support for important data binding notifications. The best thing to do would be to change both of your lists to use BindingList<T>.
It's also not a good idea for your sub-list to ever return null. It should always return an empty list, because if it returns null, the BindingManager will be unable to determine the data structure (columns) that the grid should use for the child band.
What is the status of CAS-34645-JSDCJ7? - i am having a similar issue.
I am databinding an UtraGrid to a list of MyClass objects that have only one property of the type IList<MySubClass>. The sub list is never initialized, so it is NULL.
After closing the Form that holds the Ultragrid, the MyClass objects are still kept in memory.
If i change the property to List<MySubClass>, there is no memory leak.
We have the problem in production with v. 2011.1 of the UltraGrid.
I have attached a small sample project using v. 2013.2 which reproduces the same problem.
I am using RedGate Ants Memory Profiler, and have also attached the Instance Retention Graph as pdf.
Looking forward to hear from you.
Thanks for the update.
I believe I've identified the support case you mentioned, case number CAS-34645-JSDCJ7. I've had this case assigned.
As a Standard support case, we typically provide a response time of one to three business days, which can sometimes be longer depending on our current support volume. When we can't get to them this quickly, we handle Standard cases in the order in which they were received.
At a quick glance and a discussion with some colleagues, this will clearly take further investigation to determine what's happening. This research is best performed through the support case.
Thanks for your patience.