【问题标题】:WPF element host memory leakWPF 元素主机内存泄漏
【发布时间】:2011-09-16 11:06:05
【问题描述】:

我在 Windows 窗体上使用元素主机时出现了奇怪的内存泄漏。 我有一个主窗体,它打开另一个窗体,该窗体上只有 elementhost 控件(此时,它没有 wpf 控件子级)。 只能打开 1 个主机表单。 每次打开表单,应用程序内存都会增加20Mb,当表单关闭时,这些内存不是空闲的,所以,在打开主机表单几次后,我的内存用完了!。 现在,如果我从表单中删除元素主机,内存将保持稳定。

我一直在运行 CLRProfiler 和 ANTS,但我发现所有问题都存在于元素主机上,我还没有找到任何解决方法。

wpfHost 开箱即用,只需从工具栏拖到 winForm 即可。

知道如何解决这个问题吗?

【问题讨论】:

    标签: c# .net wpf memory-leaks


    【解决方案1】:

    如果链接再次断开,这里是解决方案(复制粘贴)

    KGy 于 2010 年 10 月 22 日 6:12 发布 一种可能的解决方法: 将以下代码放入包含 ElementHost 控件的控件/表单的 Dispose 或其他释放方法中。

    if (elementHost != null)
    {
        FrameworkElement fe = elementHost.Child as FrameworkElement;
        if (fe != null)
        {
            // Memory leak workaround: elementHost.Child.SizeChanged -= elementHost.childFrameworkElement_SizeChanged;
            SizeChangedEventHandler handler = (SizeChangedEventHandler)Delegate.CreateDelegate(typeof(SizeChangedEventHandler), elementHost, "childFrameworkElement_SizeChanged");
            fe.SizeChanged -= handler;
        }
        elementHost.Child = null;
        base.Dispose(disposing);
        elementHost.Dispose();
        elementHost.Parent = null;
        elementHost = null;
    }
    

    【讨论】:

    • 嘿,我想知道你能不能解释一下你的 elementHost 对象是什么?我尝试将其替换为我的 WindowsFormsHost 对象,但不允许将其子对象转换为 FrameworkElement。
    • elementHost 是 System.Windows.Forms.Integration.ElementHost,放在一个 System.Windows.Forms.UserControl 中
    • 太棒了。 ElementHost 内存被释放。
    【解决方案2】:

    .NET 应用程序中“内存泄漏”的主要原因是事件处理程序。如果对象 A 处理对象 B 引发的事件,则对象 A 可以超出范围并且不会被销毁,因为即使您的代码不保留对它的引用,对象 B 也会。

    在 WinForms 中,一些 UI 对象(ToolStripButton 是一个很好的例子)向 Windows 注册以处理主题更改事件。 Windows 持有对它们的引用,以便它可以告诉它们用户是否更改了主题。烦人的是,这些对象不会在它们所在的表单关闭时取消注册,结果它们的表单会被销毁,但它们不会。

    那么,你到底是如何销毁这些对象之一的呢?对于ToolStripButton,将Visible 设置为false 就可以了。事实证明,切换Visible 也会切换控件是否处理主题更改事件。因此,如果您将Visible 设置为false,控件将取消注册,然后当它超出范围时,它实际上会被销毁。

    出于相同或类似的原因,这可能对ElementHost 有所帮助。很难说,因为如果你深入研究这个问题,你会发现,你知道,它并不完全记录在案。

    【讨论】:

    • 我试过这个没有运气。这正在从内存泄漏变成现在的痛苦!
    • 不要把它想成是一件让人头疼的事。将其视为学习如何使用内存分析器的机会。
    【解决方案3】:

    我的表单上有一个 WPF ElementHost 对象,并注意到内存泄漏。我正在做的事情是这样的:

    VAR cnt=this.MyHostControl.Child as MyWPFControl.WPObject;
    

    并且会在 IE 范围内执行此操作:

    Private void Myfunction()
    {
    
       VAR cnt=this.MyHostControl.Child as MyWPFControl.WPObject;
       cnt.Myproerty="Issue";
    
    }
    

    我不是VAR 的忠实粉丝(想起以前的 COM 时代),我决定创建一个像这样的全局对象:

    MyWPFControl.WPObject cnt = null;
    

    然后在FormLoad_EvenT()

    我像这样初始化对象cnt

    cnt = this.MyHostControl.Child as MyWPFControl.WPObject;
    

    现在我的参考是这样的:

    Private void Myfunction()
    {
    
       cnt=this.MyHostControl.Child as MyWPFControl.WPObject;
       cnt.Myproerty="Issue";
    
    }
    

    而且我不需要创建var 对象。

    仍在测试中,看起来它可能有效。随着时间的推移,我们会看到的。

    【讨论】:

    • 这不能解决问题。 var 是一个局部变量,您已将其切换为实例或静态变量。这永远不会减少对象在被 GC 之前存在的时间,并且可以增加它(取决于您所说的“全局对象”)。再加上问题的作者已经想出了解决他们问题的办法……
    猜你喜欢
    • 2013-04-10
    • 2011-02-21
    • 1970-01-01
    • 2010-12-05
    • 2011-03-19
    相关资源
    最近更新 更多