Windows窗体内存泄漏

我在Windows应用程序中看到了轻微的内存泄漏。 我在我的应用程序中使用DevExpress XtraForm。 我看到的是表单的一个实例总是保存在内存中。 如果多次打开相同的表单,它仍会保持打开最后一个表单的引用。

防爆。 如果你在应用程序中打开10个不同的表单并关闭所有表单,它仍然不会释放分配给它的内存,因为一些奇怪的“MdiClient对象引用了LayoutEventArgs对象”。 幸运的是,它保留了每种类型单项的参考。

这是Redgate内存分析器输出的链接。

https://dl.dropboxusercontent.com/u/2781659/Memory%20Leak.pdf

在上面的图表中,DepartmentsForm是dipined但由于LayoutEventArgs的affectedComponent成员引用它而无法进行GCed。

如果您发现任何明显错误,请告知。

从我的经验来看,Windows Forms中存在一些情况,当处置控件可以缓存在LayoutEventArgs对象中时,它看起来像WinForms中的某种小错误。

一些细节:
System.Windows.Forms.Control类型的每个实例都包含LayoutEventArgs类型的私有成员变量cachedLayoutEventArgs 。 而且, LayoutEventArgs通常包含对某些特定控件的引用。 您可以通过Reflector清楚地看到所有这些事实。 并且,有时,当子控件处理不会因某些原因影响父控件的布局过程时,不会清除cachedLayoutEventArgs字段。 您可以使用mdi父窗体模仿这种情况,方法是在关闭子窗口时挂起MdiClient的控件布局:

 public partial class MdiParentForm : Form { public MdiParentForm () { InitializeComponent(); // this.IsMdiContainer = true } void buttonAddMdiChild_Click(object sender, EventArgs e) { MdiChildForm f = new MdiChildForm(); f.MdiParent = this; f.Show(); } void buttonCloseMdiChild_Click(object sender, EventArgs e) { MdiClient client = GetMdiClient(this); client.SuspendLayout(); if(ActiveMdiChild != null) ActiveMdiChild.Close(); client.ResumeLayout(false); // !!! At this point the MdiClient.cachedLayoutEventArgs contains the reference to disposed control (leak) } static MdiClient GetMdiClient(Form frm) { if(frm != null) { foreach(Control ctrl in frm.Controls) { if(ctrl is MdiClient) return (MdiClient)ctrl; } } return null; } } class MdiChildForm : Form { } 

有一个简单的解决方法 – 通过触发PerformLayout方法,您可以有效地清除该“缓存”实例:

 class MdiChildForm : Form { MdiClient parent; protected override void OnParentChanged(EventArgs e) { base.OnParentChanged(e); var mdiClient = Parent as MdiClient; if(mdiClient != parent) { if(parent != null) parent.PerformLayout(); parent = mdiClient; } } } 

PS无论如何,我建议您在这方面联系DevExpress支持 ,以确保您描述的内存泄漏与其控件无关并获得最终解决方案。