我正在开发一个使用非常大的二进制数据集的WPF应用程序。然而,我们有巨大的内存泄漏。看起来垃圾收集器永远不会回收空间,窗口永远留在内存中。这导致了OOM问题。
以下是我们的登录窗口中的一段代码,它会在成功验证后启动MainWindow。
我明确地将mainWindow引用设置为null。但是使用点内存我可以看到当我们注销并重新登录时内存中有多个版本?这在整个应用程序中都会发生,这只是一个例子。
var mainWindow = new MainWindow();
Hide();
mainWindow.ShowDialog();
if (mainWindow.LogoutOnClose)
{
mainWindow.LogoutOnClose = false;
OmegaApp.Instance.LogOff();
mainWindow.Close();
mainWindow = null; // allow MainWindow to be garbage collected
ShowDialog();
}
else
{
Application.Current.Shutdown();
}
编辑:有些背景,我从数据库加载大量的二进制数据,所以当用户关闭那个窗口时,我需要回收那个内存。有时打开Window会分配500MB或更多。
在结束事件处理程序中添加以下部分似乎有所帮助,但仍无法解释为什么窗口本身仍保留在内存中。
private void MetroWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
// destroy render window
_miniMainModelSession.DeleteRenderWindow();
// dispose of native resources
_miniRenderer.Dispose();
_miniRenderer = null;
PreviewRenderer.Dispose();
// deallocate memory
_dialog = null;
_patientShapes = null;
_miniMainModelSession = null;
DialogResult = _cancelClose;
OmegaApp.Instance.UnregisterControl("PatientFolder");
// collect any garbage explicity
GC.Collect();
}
答案 0 :(得分:0)
您应该将所有者链接到对话框窗口。这将允许程序记住对话窗口的链接。这使得程序可以重用先前版本的对话窗口的资源。为我工作。 在我的例子中,对话框是从winform主UI启动的。所以我不得不创建一个静态的wpf所有者窗口。
的制备:将
private static Window _wpfEmptyOwnerWindowToPreventMemoryLoss = null;
public Window WpfEmptyOwnerWindowToPreventMemoryLoss()
{
if (_wpfEmptyOwnerWindowToPreventMemoryLoss==null)
{
_wpfEmptyOwnerWindowToPreventMemoryLoss = new Window();
_wpfEmptyOwnerWindowToPreventMemoryLoss.Show();
_wpfEmptyOwnerWindowToPreventMemoryLoss.Hide();
}
return _wpfEmptyOwnerWindowToPreventMemoryLoss;
}
public class WpfSelectFromList : Window
{
public WpfSelectFromList()
{
Owner = Tools.WpfEmptyOwnerWindowToPreventMemoryLoss();
}
public bool Select(...)
{
....
ShowDialog();
return ...;
}
}
答案 1 :(得分:0)
纯粹的猜测:
OmegaApp.Instance.UnregisterControl("PatientFolder");
闻起来,但这条线是安全的。它闻起来像是因为看起来你正在整合一些“Omega”,在UI层('unregistercontrol'?!),它很可能会保存对你的对象的引用(窗口或只是那个窗口的控件)并保留它们在内存中(窗口或控件,然后控制窗口)
检查完毕后,接下来要检查的是......所有事件处理程序。如果您的窗口(或几乎任何对象)永远附加到与该窗口无关的任何事件(Omega?),例如myWebClient.QueryFinished += myObj.onQueryFinished
,那么很可能这是是什么让你的窗户。您必须取消注册所有绑定到任何比您的对象长的源的事件处理程序,因为每个处理程序都记住一对:METHOD + TARGET,其中'target'是您的提供事件发生时要调用的方法的对象。