且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Windows窗体内存泄漏

更新时间:2023-12-06 09:49:16

从我的经验,在当布置控件可以在 LayoutEventArgs 对象中进行缓存的Windows窗体的一些情况它看起来像在的WinForms一些小错误的。

From my experience there are some situation in Windows Forms when disposed controls can be cached within the LayoutEventArgs object and it looks like some kind of minor bug in WinForms.

一些细节:
的每个实例的 System.Windows.Forms.Control的类型包含 LayoutEventArgs 键入一个私有成员变量 - cachedLayoutEventArgs 。而且, LayoutEventArgs 通常包含对一些特定的控制。你可以清楚地看到所有的这些事实,通过反射镜。而且,有时候, cachedLayoutEventArgs 字段不会被清除,当孩子控制优化配置,不影响父控件起诉一些原因的布局过程。您可以通过暂停MDICLIENT控制布局,同时关闭其子使用的MDI父窗体模仿这种情况:

Some details:
Each instance of the System.Windows.Forms.Control type contains a private member variable of the LayoutEventArgstype - cachedLayoutEventArgs . And, the LayoutEventArgs typically contains a reference to some specific control. You can clearly see all of these facts via Reflector. And, sometimes, the cachedLayoutEventArgs field is not cleared when the child control disposing does not affect the layout process of the parent control sue to some reasons. You can imitate this situation using the mdi parent form by suspending the MdiClient's control layout while closing its children:

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 的方法,可以有效地冲洗出的缓存的实例:

There is a simple workaround - by triggering the PerformLayout method, you can effectively flush-out that "cached" instance:

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;
        }
    }
}

P.S。在任何方式,我建议你联系 DevEx preSS支持在这方面,以确保在所描述的内存泄漏是不相关的其控制装置及获得最终的溶液

P.S. In any way I suggest you contact the DevExpress support in this regard, to sure that the memory leak you described is not related to their controls and get the final solution.