2013-03-20 107 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

相关问题