AvalonDock DocumentContent не собирает мусор - PullRequest
8 голосов
/ 15 июля 2011

Я создал приложение, которое использует фреймворк AvalonDock. Ключевой частью является возможность редактировать сущности модели домена, используя AvalonDock.DocumentContent производные редакторы. Я столкнулся с проблемой и обнаружил, что мои редакторы не собирают мусор после того, как они закрыты и удалены из коллекции DockingManager.Documents.

После некоторых бесполезных поисков я создал небольшое тестовое приложение, которое можно воссоздать следующим образом:

  • В Visual Studio (я использую 2008) создайте новое приложение WPF с именем AvalonDockLeak;
  • Добавить ссылку на библиотеку AvalonDock (моя версия 1.3.3571.0);
  • Добавить новый UserControl с именем 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 (), кстати, не помогает.

Ответы [ 5 ]

4 голосов
/ 07 января 2012

очевидно, ссылки вашего DocumentContent хранятся где-то обработчиком событий.Вы должны использовать профилировщик памяти, например CLR-Profiler от Microsoft, чтобы определить причину.

Вам следует позаботиться о том, чтобы вы всегда отменяли регистрацию зарегистрированного события.в противном случае вы можете получить утечку памяти.для этого вы можете использовать оператор - =.

3 голосов
/ 30 ноября 2011

DocumentContent по умолчанию скрывается при закрытии, что означает, что ссылка сохраняется.

Если вы хотите, чтобы DocumentContent закрывался и впоследствии утилизировался, вам нужно указать пару свойств в производном DocumentConcent или изменить источник AvalonDock.

        this.IsCloseable = true;
        this.HideOnClose = false;

Теперь, когда он закрыт, он будет распоряжаться ссылкой вместо того, чтобы висеть на ней, поскольку она просто скрывалась.

2 голосов
/ 17 января 2012

У меня тоже были проблемы в этом направлении. Закрытие вкладок может привести к утечке памяти. Я проверил это с помощью профилировщика, и оказалось, что ActiveContent будет по-прежнему сохранять ссылку, предотвращая срабатывание GarbageCollector.

мой код для закрытия вкладки:

dc // DocumentContent, I want to close it
documentPane // DocumentPane, containing the dc

documentPane.Items.Remove(dc);

это сделало работу по закрытию вкладки, но узнал, что мне нужно позвонить

dc.Close();

перед удалением содержимого из панели документов, если я хочу, чтобы ActiveContent было установлено на null и чтобы ГХ выполнял свою работу.

Примечание: Я использую AvalonDock версии 1.2, возможно, это изменилось в более новых версиях.

1 голос
/ 19 ноября 2012

Я настоятельно рекомендую вам и всем, кто использует AvalonDock 1.3, перейти на версию 2.0.Последняя версия является MVVM-дружественной и не страдает от этой проблемы (Документы и анкеры правильно собирают мусор).Больше информации: avalondock.codeplex.com

Спасибо

1 голос
/ 24 февраля 2012

Это похоже на давно выдающуюся ошибку ...:

http://avalondock.codeplex.com/workitem/9113

...