2011-07-15 59 views
8

我已經創建了一個使用AvalonDock框架的應用程序。關鍵部分是使用派生編輯器編輯域模型實體的能力。我遇到了一個問題,並發現我的編輯在關閉並從DockingManager.Documents集合中刪除後沒有進行垃圾回收。AvalonDock DocumentContent未垃圾回收

後,我創建了一個可以通過以下方式來重新創建一個小的測試應用程序的一些無覓處:

  • 在Visual Studio(我使用的是2008年),創建一個名爲AvalonDockLeak一個新的WPF應用程序;
  • 添加對AvalonDock庫的引用(我的版本是1.3.3571.0);
  • 添加一個名爲Document的新UserControl;
  • 更改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()沒有幫助的方式。

+0

檢查Avalon的源代碼,看看有什麼'document.Show(this.DockManager);'一樣。我猜文檔會以某種方式向管理員註冊,而且它沒有正確註銷。 DockManager上是否有方法去除文檔? – ChrisWue

+0

它只是'manager.Documents.Add(this);'。文檔關閉後,它也不再存在於'manager.Documents'集合中。 – Wietze

+0

那麼,找出的一種方法是附加一個內存分析器或進行內存轉儲,並使用windows的調試工具來找出引用的內容。 – ChrisWue

回答

1

我強烈建議你使用AvalonDock 1.3人升級到2.0版本。 最新版本是MVVM友好的,不會遇到這個問題(文檔和Anchorables被正確地垃圾收集)。 更多信息:avalondock.codeplex.com

感謝

+0

似乎沒有一個從1.3到2.0的簡單升級路徑 - 例如,佈局元素不再從FrameworkElement類派生。 MVVM看起來不錯,但:-) – Dunc

+0

不,這不容易,但它做了訣竅加一些。偉大的工作@adospace。 – Wietze

3

DocumentContent將默認隱藏在關閉位置,這意味着引用保持活動狀態。

如果您想讓DocumentContent關閉並隨後處置,您需要在派生的DocumentConcent中指定幾個屬性或修改AvalonDock源。

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

現在關閉時,它會銷燬該引用的對比,因爲它僅僅是被隱藏掛到它。

+0

** HideOnClose屬性在DocumentContent-Class **中不存在(僅在DockableContent中)!我有像開瓶器一樣的問題。如果我調試派生的DocumentContent類我可以看到,如果你點擊Clsoing符號OnClosing() - 處理程序被稱爲,但不是類的Desctructor。所以**如何關閉DocumentContent-Instance?** – 0xDEADBEEF

+0

@ 0xDEADBEEF「DocumentContent」不包含「HideOnClose」屬性是正確的。你是否嘗試過繼續添加'DocumentContent'實例,然後關閉它們,多次執行此操作,並通過內存分析器觀察內存是否不斷爬升或GC是否運行並回收內存?現在忽略不被調用的析構函數。 –

+0

是的。我開了50個實例。我可以在堆中找到它們。我關閉了他們,並開了100多個。我已經做了2次。他們都是(250例)留在堆裏 - >記憶力不會減少。調用GC.Collect()手動不起作用 – 0xDEADBEEF

4

顯然,DocumentContent的引用由某個事件處理程序保存。你應該使用微軟的CLR-Profiler這樣的內存分析器來確定原因。

你應該注意,你總是註銷註冊的事件。否則你可能會發生內存泄漏。爲此,您可以使用 - =運算符。

2

我在這方面也有問題。關閉標籤會導致內存泄漏。我有一個分析器檢查,它原來,ActiveContent仍然會保持一個參考,防止GarbageCollector在踢

我關閉的標籤代碼:

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

documentPane.Items.Remove(dc); 

這個做的工作的關閉標籤,但得知我需要去除的documentPane內容之前調用

dc.Close(); 

,如果我想ActiveContent設置爲null並讓GC做它的工作。

注:我使用1.2版的AvalonDock,這可能在更新的版本中有所變化。