我们目前正在用WPF重新开发一个WindowsForms应用程序。这个软件相当大,需要几年的时间才能完成,因此我们有一个混合系统,它为新面板显示纯WPF,并在WindowsFormsHosts控件中显示托管WindowsForms元素。(不确定此信息是否相关)。我们花了相当多的时间来跟踪内存泄漏(使用JetBrains的DotMemory),但在打开和关闭了近100个包含WindowsFormsHosts的页面后,我们耗尽了内存。
这种内存泄漏相当奇怪,正如您在内存分析中所看到的,问题似乎出在非托管内存中。
DotMemory profiling
WindowsFormsHosts和子内容似乎都已正确处置。如此处WPF WindowsFormsHost memory leak所建议的,我们将WindowsFormsHosts Package 在网格中,在需要处置时清除该网格:
public override void Dispose()
{
if (this.Content is Grid grid && grid.Children.Count == 1)
{
if (grid.Children[0] is KWFHost wfh)
{
wfh.Child.SizeChanged -= ControlSizeChanged;
wfh.Dispose();
}
grid.Children.Clear();
}
base.Dispose();
}
以及
public class KWFHost : WindowsFormsHost
{
protected override void Dispose(bool disposing)
{
if (this.Child is IDisposable disposable)
{
disposable.Dispose();
}
this.Child = null;
base.Dispose(true);
}
}
我们怀疑是托管导致了泄漏,因为在DotMemory中,在内存分配中我们可以看到:
memory allocation
WindowsFormsHosts是否有任何已知的问题可以解释这一点?或者我们可以找到一种方法来隔离问题的根源?
编辑:下面是添加网格和WindowsFormHost的代码:
public void SetContent(System.Windows.Forms.Control control)
{
var host = new KWFHost();
host.Child = control;
control.SizeChanged += ControlSizeChanged;
var grid = new Grid();
grid.Children.Add(host);
this.Content = grid;
}
1条答案
按热度按时间vojdkbi01#
我终于想通了:经过进一步的挖掘,我发现WindowsFormsHosts是保持活动的。DotMemory给了我两个原因。
System.Windows.Interop.HwndSourceKeyboardInputSite
。由于我无法解释的原因,HwndSource的ChildKeyboardInputSinks中仍然存在对WindowsFormsHost的引用。如果有人知道原因,我会很想听听原因。我不知道是否有更好的方法来消除此引用,但以下是我编写的代码:我在释放WindowsFormsHost之前执行此方法。
RootSourceRelationManager
。这个让我头疼。所以我做了一个“完整”的点内存分析(之前是抽样),结果很奇怪,内存泄漏消失了。完整的分析需要从Dotmemory而不是Visual Studio执行。这是唯一的区别。经过一些研究,我发现涉及到Microsoft.Visual.Design Tools.WpfTap.wpf
。所以看起来(我不能肯定)从visual studio执行会导致内存泄漏(这并不严重,但知道这一点是件好事)。最后,在发布了使用clean方法的软件的新测试版本后,我不再有内存泄漏。