Reputation: 412
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.
Upvotes: 8
Views: 3730
Reputation: 2019
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
Upvotes: 1
Reputation: 4665
This looks like a long time outstanding bug...:
http://avalondock.codeplex.com/workitem/9113
Upvotes: 1
Reputation: 959
I also had a problem in this direction. Closing tabs would cause memory leaks. I checked it with a profiler and it turned out that the ActiveContent would still keep a reference, preventing the GarbageCollector to kick in.
my code for closing the tab:
dc // DocumentContent, I want to close it
documentPane // DocumentPane, containing the dc
documentPane.Items.Remove(dc);
this did the job of closing the tab, but learned that I need to call
dc.Close();
before removing the content from the documentPane if I want ActiveContent to be set to null and let the GC do it's job.
Note: I use version 1.2 of AvalonDock, this may have changed in newer versions.
Upvotes: 1
Reputation: 657
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.
Upvotes: 5
Reputation: 24713
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.
Upvotes: 3