Windows Form Memory leak

不想你离开。 提交于 2019-12-06 07:36:07

问题


I see a slight memory leak in my windows application. I use DevExpress XtraForm in my application. What I see is one instance of the form is always being kept in memory. If you open the same form multiple times it still keeps the reference of last form opened.

Ex. if you open 10 different form in the application and close all of them it would still not release the memory assigned to it because of some weird "MdiClient object references LayoutEventArgs object". Fortunately it keep reference of single item per type.

Here is the link to the Redgate memory profiler output.

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

In the chart above the DepartmentsForm is diposed but cannot be GCed because of affectedComponent member of LayoutEventArgs referencing it.

Please advise if you see any obvious error.


回答1:


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.

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

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. 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.



来源:https://stackoverflow.com/questions/25181679/windows-form-memory-leak

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!