GarbageCollector的替代品是什么?

Gre*_*reg 8 .net c# wpf garbage-collection

我有以下代码,它将OutOfMemoryException在运行时生成:

public partial class MainWindow : Window
{
    private DrawingVisual myVisual = new DrawingVisual();

    public MainWindow()
    {
        InitializeComponent();
    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        myVisual = GetVisual();
        graphicsCanvas.AddVisual(myVisual);
    }

    private void Graphics_Canvas_MouseMove(object sender, MouseEventArgs e)
    {
        //get the data visual:
        DrawingVisual tempVisual = GetVisual();

        //first clear the current display data:
        graphicsCanvas.RemoveVisual(myVisual);

        //get the data visual:
        myVisual = tempVisual;

        graphicsCanvas.AddVisual(myVisual);

        //GC.Collect();
    }

    private DrawingVisual GetVisual()
    {
        double width = graphicsCanvas.ActualWidth;
        double height = graphicsCanvas.ActualHeight;

        DrawingVisual dV = new DrawingVisual();

        Rect clipRect = new Rect(0, 0, width, height);

        dV.Clip = new RectangleGeometry(clipRect);

        using (DrawingContext dC = dV.RenderOpen())
        {
            RenderTargetBitmap rTB = new RenderTargetBitmap((int)width, (int)height, 96, 96, PixelFormats.Pbgra32);

            if (rTB.CanFreeze)
            {
                rTB.Freeze();
            }

            dC.DrawImage(rTB, clipRect);
        }

        return dV;
    }
}
Run Code Online (Sandbox Code Playgroud)

a Graphics_Canvas的定义如下:

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++)
        {
            RemoveFromLogicalTree(visuals[i]);
        }

        visuals.Clear();
    }

    private void RemoveFromLogicalTree(Visual visual)
    {
        RemoveLogicalChild(visual);
        RemoveVisualChild(visual);
    }

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

            RemoveFromLogicalTree(visuals[index]);
            visuals.Remove(visuals[index]);
        }     
    }

    public void RemoveVisual(DrawingVisual visual)
    {
        RemoveFromLogicalTree(visual);
        visuals.Remove(visual);            
    }
}
Run Code Online (Sandbox Code Playgroud)

并且创建的XAML Window是这样的:

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:csMemoryLeakTestProject" x:Class="csMemoryLeakTestProject.MainWindow"
    Title="MainWindow" 
    Background="Gray"
    Height="600" Width="800"
    WindowStartupLocation="CenterScreen"
    Loaded="Window_Loaded">
    <Grid>
        <local:Graphics_Canvas Margin="12" Background="White" x:Name="graphicsCanvas" MouseMove="Graphics_Canvas_MouseMove"/>
    </Grid>
</Window>
Run Code Online (Sandbox Code Playgroud)

现在,这只是一个例子来说明我的观点,即我不明白使用垃圾收集器的替代方法是什么...

如果您运行该程序,并继续将鼠标移动到该程序上Graphics_Canvas,则内存使用构建,构建和构建,直到您获得OutOfMemoryException.如果你添加GC.Collect()我评论它的地方,这不会发生(虽然内存确实增加了一小部分,因为超出我的原因,并希望与我的问题相关联),程序继续运行.

那么,为什么不GC启动并清除此内存并停止发生异常?如果我正在做一些非常根本性的错误,我会很高兴有人向我指出,以便我可以超越这个.

我在这个网站上看到很多次,其他人也从程序员那里得到了"永远不要使用垃圾收集器"的建议.我想要遵循最佳实践,但我不会在这样的情况下看到我还能做什么.

Tig*_*ran 10

GC程序无法管理太多内存并不是错误.在你的程序中你做:

private void Graphics_Canvas_MouseMove(object sender, MouseEventArgs e)
{
   ....
    //ADD ELEMENTS ON EVERY MOVE !
    graphicsCanvas.AddVisual(myVisual);

    //GC.Collect();
}
Run Code Online (Sandbox Code Playgroud)

Tou为每个鼠标移动添加元素,因此增加集合大小.你会期待什么?

因此,在90%的情况下,针对这类问题的解决方案是重新构建您的代码.

例:

每次将新元素添加到chidren视觉集合时,您几乎不可能在MouseMove上添加.可能是重用已经存在的情况.

GC不建议明确使用,但有时我们需要使用它.但是,我再说一遍,我简直不敢相信,在这种情况下,你需要以这种方式管理程序.

  • 等等,代码首先*删除*元素然后添加另一个元素.没关系. (4认同)
  • 说实话; 我觉得很奇怪,系统会在**尝试`GC.Collect()`之前抛出一个`OutOfMemoryException`**.只是我的两分钱. (2认同)
  • @Tigran那不是我的意思。我的观点是,这是GC可以正常使用的可接受的使用模式。您的答案强烈暗示该代码只是将对象添加到集合中而没有删除它们,并且OP的代码正在导致内存泄漏。不是这种情况。 (2认同)