加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – Windows窗体内存泄漏

发布时间:2020-12-16 02:02:48 所属栏目:百科 来源:网络整理
导读:我在 Windows应用程序中看到了轻微的内存泄漏.我在我的应用程序中使用DevExpress XtraForm.我看到的是表单的一个实例总是保存在内存中.如果多次打开同一个表单,它仍会保持打开最后一个表单的引用. 防爆.如果你在应用程序中打开10个不同的表单并关闭所有表单,
我在 Windows应用程序中看到了轻微的内存泄漏.我在我的应用程序中使用DevExpress XtraForm.我看到的是表单的一个实例总是保存在内存中.如果多次打开同一个表单,它仍会保持打开最后一个表单的引用.

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

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

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

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

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

解决方法

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

一些细节:
System.Windows.Forms.Control类型的每个实例都包含LayoutEventArgstype的私有成员变量–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;
        }
    }
}

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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读