I have created an application that makes use of the AvalonDock framework. A key part is the ability to edit domain-model entities using AvalonDock.DocumentContent
derived editors. I hit upon a problem and discovered the my editors are not being garbage collected after they are closed and removed from the DockingManager.Documents
collection.
After some fruitless searching I created a small test application that can be recreated in the following manner:
AvalonDockLeak
;Document
;Change Document.xmal to:
<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>
Change Document.xmal.cs to:
namespace AvalonDockLeak
{
using AvalonDock;
public partial class Document : DocumentContent
{
public Document()
{
InitializeComponent();
}
~Document()
{
}
}
}
The destructor I have added to be able to diagnose the problem adding a breakpoint on the methods opening {, and seeing if it gets hit. It always does on closing the test application but not earlier.
Now change Window1.xaml to:
<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>
Change Window1.xaml.cs to:
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();
}
}
}
This simple application also contains the leak. Which can be observed by the breakpoint on the ~Document()
opening { not getting hit after closing a DocumentContent
.
Now what I want to now is, is this a known problem and is there a way to prevent it? If the objects are only garbage collected after a long time then what can I do to expedite this? Calling GC.Collect() does not help by the way.
obviously the references of your DocumentContent is kept by an eventhandler somewhere. you should use a memory-profiler like CLR-Profiler from microsoft to determine the cause.
you should take care that you always deregister an registered event. otherwise you can get a memory leak. for this you can use the -= operator.
The DocumentContent
will by default hide on close, which means the reference is kept alive.
If you want the DocumentContent
to close and subsequently dispose you need to specify a couple of properties within a derived DocumentConcent
or modify the AvalonDock
source.
this.IsCloseable = true;
this.HideOnClose = false;
Now when closed, it will dispose of the reference versus hanging on to it as it was merely being hidden.
I strongly suggest you and anyone using AvalonDock 1.3 to upgrade to version 2.0. Latest version is MVVM-friendly and doesn't suffer of this issue (Documents and Anchorables are correctly garbage collected). More info: avalondock.codeplex.com
Thanks
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With