2013-03-20 56 views
1

我有一個使用Canvas一個Window內的WPF程序,過度纏身,成爲Graphics_Canvas,它看起來像這樣:爲什麼連續移除和重新添加DrawingVisual會導致內存使用量不斷增加?

class Graphics_Canvas : Canvas 
{ 
    private List<DrawingVisual> visuals = new List<DrawingVisual>(); 

    protected override int VisualChildrenCount 
    { 
     get { return visuals.Count; } 
    } 

    protected override Visual GetVisualChild(int index) 
    { 
     return visuals[index]; 
    } 

    public void AddVisual(DrawingVisual visual) 
    { 
     visuals.Add(visual); 

     base.AddVisualChild(visual); 
     base.AddLogicalChild(visual); 
    } 

    public bool ContainsVisual(DrawingVisual visual) 
    { 
     return visuals.Contains(visual); 
    } 

    public bool HasVisuals 
    { 
     get { return visuals.Count > 0; } 
    } 

    public void RemoveAllVisuals() 
    { 
     for (int i = 0; i < visuals.Count; i++) 
     { 
      base.RemoveVisualChild(visuals[i]); 
      base.RemoveLogicalChild(visuals[i]); 
     } 

     visuals.Clear(); 
    } 

    public void RemoveLastVisual() 
    { 
     if (visuals.Count > 0) 
     { 
      int index = visuals.Count - 1; 

      base.RemoveVisualChild(visuals[index]); 
      base.RemoveLogicalChild(visuals[index]); 
      visuals.Remove(visuals[index]); 
     }  
    } 

    public void RemoveVisual(DrawingVisual visual) 
    { 
     base.RemoveVisualChild(visual); 
     base.RemoveLogicalChild(visual); 
     visuals.Remove(visual);    
    } 
} 

(我沒有得到從某處在線,但我不記得在哪裏)

無論如何,該程序允許用戶通過拖動中間的鼠標來平移顯示在Graphics_Canvas上的圖形,並且這將持續(只要它們保持平移)觸發像這樣的東西:

  //get the data visual: 
      DrawingVisual tempVisual = GetDataDrawingVisual(); 

      //first clear the current display data: 
      myCanvas.RemoveVisual(dataVisual); 

      //get the data visual: 
      dataVisual = tempVisual; 

      myCanvas.AddVisual(dataVisual); 

所以我不斷刪除,然後重新添加dataVisual

當我看到內存使用時,我注意到,平移會導致內存使用增加,而當它再次下降時,它不會一直保持原來的狀態。當顯示屏上完全沒有顯示時,這一點更加明顯,並且內存使用不斷地重新添加任何東西都可能會增加到幾百MB,而在平移停止時主要再次下降。

有關信息,我應該補充說明GetDataDrawingVisual()返回一個Visual,其上繪製了一個RenderTargetBitmap,它本身不保留在該方法之外。

我的問題是爲什麼這會導致內存使用變化如此之多?

目前這更多的是一個奇怪的麻煩,但我可以預見,如果可用內存更有限,可能是一個問題。

任何見解將不勝感激。

* UPDATE(21/03/2013)*

從與Graphics_Canvas試驗,看來下面的方法使多少內存公平的影響尚未發佈:

protected override Visual GetVisualChild(int index) 
{ 
    return visuals[index]; 
} 

如果我只是將new DrawingVisual()作爲測試返回,則內存回到幾乎在重新繪製結束後的位置。

但是,刪除此方法只是意味着Canvas將不會運行,並且會出現錯誤。難道是在幕後.NET的某個地方引用了從這個方法返回的Visual,然後沒有去引用它?我怎麼能解決這個問題? (注意:我從來沒有明確地在我的代碼中調用這個方法,它是從其他地方調用的)。

+0

在你展示的代碼,視覺您刪除(dataVisual),可能不一樣的,你要添加的一個。你能顯示getDataDrawingVisual代碼嗎? – GameAlchemist 2013-03-20 12:23:08

+0

@VincentPiel真的,它不會總是一樣的,因爲我會改變畫布上的圖形。但是對於上面的例子,我始終生成一個完全空白的圖像,這是因爲Visual的內容沒有任何變化,這讓我覺得在某個地方存在問題。該方法的代碼擴展爲子例程的加載,因此非常冗長,完成的操作取決於用戶設置和加載到程序中的文件數量,因此添加它可能不容易或特別有用。 – Greg 2013-03-20 12:29:22

+0

如果你正在創建一個新的Canvas對象,爲什麼你會期望內存使用不增加? – 2013-03-20 12:38:25

回答

1

我認爲你的內存使用量變化很大的原因是garbage collector不馬上踢。所以,當你拖動周圍的對象時,會建立內存使用情況,直到它運行。

你可以通過執行強制垃圾回收:

GC.Collect(); 
GC.WaitForPendingFinalizers(); 

這樣,你就知道。

關於爲什麼你的記憶不會一直回來:也許你保持對你的一些視覺效果的引用,而那些沒有收集到?也許程序的其他部分正在建立內存?

你可能有內存泄漏,您可以查看這篇文章WPF Performance and .NET Framework Client Profile

+0

我在我的程序中有幾個手動調用GC的情況,但是這些只是在關閉大文件時。我厭倦這樣做,因爲這裏和其他地方的主要觀點似乎永遠不會手動調用GC。 – Greg 2013-03-20 12:45:42

+1

顯式調用GC被認爲是不好的做法。確保在這種情況下您沒有其他方式來釋放資源。 你可以查看這篇文章:http://msdn.microsoft.com/en-us/library/66x5fx1b.aspx「顯式釋放資源」部分建議實現IDisposable。在這裏你有一篇關於如何做到這一點的文章:http://www.codeproject.com/Articles/413887/Understanding-and-Implementing-IDisposable-Interfa – Dzyann 2013-03-20 16:04:08

+0

謝謝,我沒有在這種情況下使用GC。此外,DrawingVisual和RenderTargetBitmap不實現IDisposable,所以我不能在這裏做到這一點。從一些進一步的測試來看,這似乎是由RenderTargetBitmap引起的。我做了一個測試,返回一個沒有增加內存的空DrawingVisual,但是當我繪製一個空的RenderTargetBitmap時,內存隨着不斷的重繪而迅速增加。當我停下來,它下降,但不是原來的水平。 – Greg 2013-03-20 16:52:07

相關問題