Windows窗体内存泄漏窗体、内存、Windows

2023-09-03 01:47:30 作者:困成憨包

我看到在我的Windows应用程序中有轻微的内存泄漏。我用DevEx preSS XtraForm在我的应用程序。我看到的是形式的一个实例总是被保存在内存中。如果你打开​​同一形式多次仍保留了最后一种形式的参考打开。

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.

例。如果你打开​​应用程序中的10种不同的形式,并关闭所有的人都将仍然不会释放分配的,因为一些奇怪的MDICLIENT对象引用LayoutEventArgs对象的给它的内存。幸运的是它让每个类型的单个项目的参考。

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

在图表上面的DepartmentsForm是diposed但也不能因为LayoutEventArgs引用它的affectedComponent成员GCed。

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.

推荐答案

从我的经验,在当布置控件可以在 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.