Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AvalonDock DocumentContent not garbage collected

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:

  • In Visual Studio (I'm using 2008), create a new WPF application called AvalonDockLeak;
  • Add a reference to the AvalonDock library (my version is 1.3.3571.0);
  • Add a new UserControl called 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.

like image 746
Wietze Avatar asked Jul 15 '11 09:07

Wietze


3 Answers

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.

like image 116
Sheldon Cooper Avatar answered Sep 28 '22 17:09

Sheldon Cooper


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.

like image 36
Aaron McIver Avatar answered Sep 28 '22 18:09

Aaron McIver


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

like image 25
adospace Avatar answered Sep 28 '22 18:09

adospace