WPF元素宿主内存泄漏

9
我在使用Windows Forms的元素宿主时遇到了奇怪的内存泄漏问题。 我有一个主窗体,它打开另一个窗体,这个窗体上只有元素宿主控件(此时没有WPF控件子项)。 只能打开1个宿主窗体。 每次打开窗体时,应用程序的内存会增加20Mb,关闭窗体后这些内存不会被释放,因此,打开宿主窗体多次后,我就没有内存可用了! 现在,如果我从窗体中删除元素宿主,则内存保持稳定。
我一直在运行CLRProfiler和ANTS,但我发现所有问题都存在于元素宿主上,我没有找到任何解决方法。
wpfHost是开箱即用的,只需从工具栏拖动到winForm中。
有什么想法如何解决这个问题吗?
3个回答

8
如果链接再次中断,这里提供解决方案(复制粘贴即可)。
发布者为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是不允许的。 - user2088807
elementHost 是 System.Windows.Forms.Integration.ElementHost,它被放置在 System.Windows.Forms.UserControl 内部。 - ncat
太好了。ElementHost的内存已经释放。 - nyconing

2
".NET应用程序中“内存泄漏”的主要原因是事件处理程序。如果对象A处理对象B引发的事件,即使代码没有保留对其的引用,对象B也会保留对它的引用,因此对象A可能超出范围而无法被销毁。在WinForms中,一些UI对象(ToolStripButton是一个很好的例子)注册Windows来处理主题更改事件。Windows保存对它们的引用,以便在用户更改主题时通知它们。令人恼火的是,这些对象不会在它们所在的窗体关闭时注销,导致它们所在的窗体被销毁但它们却没有被销毁。那么该如何销毁这些对象呢?对于ToolStripButton,将Visible设置为false就可以解决问题。事实证明,切换Visible还会切换控件是否处理主题更改事件。因此,如果将Visible设置为false,则控件将注销,然后当它超出范围时,它实际上可以被销毁。也许这对于ElementHost有帮助,因为出于同样或类似的原因。很难说,因为如果您深入研究此问题,您会发现它并没有得到充分的记录。"

我已经尝试过了,但没有成功。现在这个问题从内存泄漏变成了一个十分麻烦的事情! - Mg.
不要把它看作是一件烦心事。把它看作是学习如何使用内存分析器的机会。 - Robert Rossney

-1
我在我的表格上有一个 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对象。

仍在测试中,看起来可能正在工作。随着时间的推移我们会看到。


2
这样做并不能解决问题。var是一个本地变量,而你已经将其转换为实例或静态变量。这永远不会减少对象在被GC回收之前存在的时间,并且可能会增加它(取决于你对“全局对象”所指的内容)。此外,问题的作者已经找到了解决方案... - Merlyn Morgan-Graham

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接