当窗口有一个带有TabItem的TabControl(或延迟内存回收?)时,C#WPF内存泄漏
我在一个应用程序中遇到了一个非常明显的内存泄漏,该应用程序将打开一个设置窗口,其中包含一个包含许多TabItems的TabControl。起初,我认为其中一个显示的用户控件一定是罪魁祸首,于是我注释了一大堆东西,最后拿出JetBrains dotMemory并制作了一个演示程序 这个问题(我想) 当窗口包含至少包含一个TabItem的TabControl时,当窗口关闭时,窗口对象仍然存在。如果TabControl中没有TabItems,窗口对象将立即销毁(如预期的那样) 保留期 根据dotMemory,“保留”来自WindowAutomationPeer(.\u所有者)、TabControlAutomationPeer(.\u父对象)、TabItemAutomationPeer(.\u父对象)、ElementProxy(.\u父对象),然后在底部显示“RefCounted handle” 复制 创建一个名为“TabsInWindows”的新C#WPF应用程序(目标框架:.NETFramework 4.7.2) 将按钮添加到主窗口:当窗口有一个带有TabItem的TabControl(或延迟内存回收?)时,C#WPF内存泄漏,c#,wpf,memory-leaks,tabcontrol,tabitem,C#,Wpf,Memory Leaks,Tabcontrol,Tabitem,我在一个应用程序中遇到了一个非常明显的内存泄漏,该应用程序将打开一个设置窗口,其中包含一个包含许多TabItems的TabControl。起初,我认为其中一个显示的用户控件一定是罪魁祸首,于是我注释了一大堆东西,最后拿出JetBrains dotMemory并制作了一个演示程序 这个问题(我想) 当窗口包含至少包含一个TabItem的TabControl时,当窗口关闭时,窗口对象仍然存在。如果TabControl中没有TabItems,窗口对象将立即销毁(如预期的那样) 保留期 根据dotMem
<Window x:Class="TabsInWindows.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="MainWindow" Height="300" Width="300">
<Grid>
<Button Content="Open tab window" Click="Button_Click"/>
</Grid>
</Window>
启动应用程序。每次按下按钮时,都会创建一个新窗口,但TabItem(?)会在窗口关闭时保留,因此TabWindow也会保留。(重复任意次数)
如何修复?
我的问题是,在我的实际应用程序中,所有选项卡的所有内容似乎都保留在内存中,导致了严重的内存泄漏
在演示应用程序中,我尝试过做一些事情来避免挂起的物体;将网格的内容设置为null。清除选项卡控件(主题)中的项目。清除网格中的子元素。
所有这些都不起作用
我不知道什么是“AutomationPeer”-对象,或者ElementProxy是由什么创建的,以及为什么它不会消亡
如果有人能告诉我如何避开这个问题,或者能解释什么是ElementProxy以及它为什么会出现,这将是非常有帮助的
在写这篇文章时,我确实让dotMemory与测试应用程序一起运行,在最后做了一件事之后,这些对象似乎已经被删除了
这就引出了一个问题:在移除一个对象之前,我能期望它在内存中有多长时间是可见的,并且带有引用
在实际项目中
然后,我在实际项目中尝试了类似的方法,确保非我们自己的控件直接链接到SettingsWindow(我不排除我们的一个控件中存在内存/引用问题,因此直接在“键保留路径”中列出的任何控件都已注释掉)。
剩下的“3个唯一分支”,一个是来自ListBox自身扩展的“EffectiveValueEntry[40]”,另两个是“EffectiveValueEntry”([19]和[22]),都来自TextBlock、TextBlockAutomationPeer[4]、List、ListBoxItemAutomationPeer、ElementProxy
在大约十分钟的无所事事后,设置Swindow仍然存在,但“密钥保留路径”已更改,“20个唯一分支”都是有效的ValueEntry(第一个是[32],其余是[42])、TextBox、TextEditor,但现在“F-Reachable Queue”位于列表底部
又过了大约十分钟,布景终于消失了
然后,我又打开了设置窗口几次,在关闭最后一个窗口一分钟后,只有“文本框”(TextBox)引用离开了,随后强制垃圾收集(使用dotMemory中的按钮),对象引用消失了
该相信什么?
所以很明显,如果我等待足够长的时间,“魔法”就会发生——但这是一台电脑——不是魔法盒
有谁能告诉我为什么有些物体会在记忆中出现更长时间,但最终会被移除?我应该期望这些物体在我周围停留多久
我还想找到一种方法来防止这些“鬼”对象出现在TabItems中,如果它们最终会被删除,那么它们就没有理由占用内存。。。
你看,我在SettingsWindow中对一些UI组件进行性能测试时发现了这一点,并且随着内存的使用,重复测试花费的时间越来越长,因此简单地等待引用消失并不是一个很好的选择
如果你无能为力;感谢您抽出时间阅读我的文字墙…设置选项卡窗口的所有者
private void Button_Click(object sender, RoutedEventArgs e)
{
TabsWindow w = new TabsWindow();
w.Owner = this;
w.Show();
}
设置选项卡窗口的所有者
private void Button_Click(object sender, RoutedEventArgs e)
{
TabsWindow w = new TabsWindow();
w.Owner = this;
w.Show();
}
您所看到的是,有证据表明该窗口没有及时清除其引用(资源),并且没有资格进行后续的第2代垃圾收集。GC应该在需要获取更多内存时收集您的窗口,正如您所说,该窗口稍后会被收集,这意味着它迟早会消失。@XAMlMAX有办法强制它清理吗?我知道这不是最好的解决方案,但您可以尝试调用
GC.Collect()代码>完成后,但不是在关闭事件上。我不能保证这会有帮助,或者它会收集物品,但值得一试。垃圾收集的链接。@XAMlMAX我怀疑这会有什么不同,因为在界面上按那个按钮时,它几乎没有效果。我已经尝试过关闭和删除内容的所有选项卡,这似乎有助于更快地回收包含的某些对象。空的TabItem至少比包含对象的TabItem占用更少的内存。为什么您关心内存的回收速度?您看到的证据表明,该窗口没有及时清除其引用(资源),并且有资格进行后续的第2代垃圾回收。GC应该在需要获取更多内存时收集您的窗口,正如您所说,该窗口稍后会被收集,这意味着它迟早会消失。@XAMlMAX有办法强制它清理吗?也许我能做点什么
private void Button_Click(object sender, RoutedEventArgs e)
{
TabsWindow w = new TabsWindow();
w.Owner = this;
w.Show();
}