【发布时间】:2011-07-15 09:55:43
【问题描述】:
我创建了一个使用 AvalonDock 框架的应用程序。一个关键部分是使用AvalonDock.DocumentContent 派生编辑器编辑域模型实体的能力。我遇到了一个问题,发现我的编辑器在关闭并从 DockingManager.Documents 集合中删除后没有被垃圾回收。
经过一番徒劳的搜索后,我创建了一个可以通过以下方式重新创建的小型测试应用程序:
- 在 Visual Studio(我使用的是 2008)中,创建一个名为
AvalonDockLeak的新 WPF 应用程序; - 添加对AvalonDock库的引用(我的版本是1.3.3571.0);
- 添加一个名为
Document的新用户控件; -
将 Document.xmal 更改为:
<ad:DocumentContent x:Class="AvalonDockLeak.Document" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:ad="clr-namespace:AvalonDock;assembly=AvalonDock"> <Grid> <TextBox /> </Grid> </ad:DocumentContent> -
将 Document.xmal.cs 更改为:
namespace AvalonDockLeak { using AvalonDock; public partial class Document : DocumentContent { public Document() { InitializeComponent(); } ~Document() { } } }我添加的析构函数能够诊断问题,在打开 { 的方法上添加断点,并查看它是否被命中。它总是在关闭测试应用程序时这样做,但不是更早。
-
现在将 Window1.xaml 更改为:
<Window x:Class="AvalonDockLeak.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:ad="clr-namespace:AvalonDock;assembly=AvalonDock" Title="Memory Leak Test" Height="300" Width="300"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition /> </Grid.RowDefinitions> <Button Name="NewButton" Click="NewButton_Click" Content="New" Height="26" Width="72" /> <ad:DockingManager x:Name="DockManager" Grid.Row="1"> <ad:DocumentPane /> </ad:DockingManager> </Grid> </Window> -
将 Window1.xaml.cs 更改为:
namespace AvalonDockLeak { using System.Windows; public partial class Window1 : Window { private int counter = 0; public Window1() { InitializeComponent(); } private void NewButton_Click(object sender, RoutedEventArgs e) { string name = "Document" + (++this.counter).ToString(); var document = new Document() { Name = name, Title = name, IsFloatingAllowed = false }; document.Show(this.DockManager); document.Activate(); } } }
这个简单的应用程序也包含泄漏。这可以通过~Document() 开头的断点观察到{关闭DocumentContent 后没有被命中。
现在我想要的是,这是一个已知问题吗?有没有办法防止它?如果对象只是在很长一段时间后才被垃圾收集,那么我能做些什么来加快这一点?顺便说一下,调用 GC.Collect() 也无济于事。
【问题讨论】:
-
检查 Avalon 源代码,看看
document.Show(this.DockManager);做了什么。我猜该文件以某种方式向经理注册,并且没有正确取消注册。 DockManager 上是否有删除文档的方法? -
它只是做
manager.Documents.Add(this);。关闭文档后,它也不再存在于manager.Documents集合中。 -
嗯,找出答案的一种方法是附加内存分析器或进行内存转储并使用 Windows 调试工具来找出持有引用的内容。
标签: c# wpf garbage-collection avalondock