WriteableBitmap复制内存泄漏

时间:2018-10-20 19:51:26

标签: c# wpf memory-leaks writeablebitmap

我正在研究WriteableBitmaps,并且有一种方法可以实现:

  1. WriteableBitmap从参数复制到方法外部的变量
  2. 在第一个位图上工作
  3. 将复制的位图添加到UndoStack

此方法的重点是在位图上进行更改,然后在更改前将其添加到撤消堆栈位图。

如果经常调用此方法,则会导致OutOfMemoryException

变量

private WriteableBitmap _oldBitmap;
private Image _oldImage;

方法

public Layer ExecuteTool(Layer layer, Coordinates startingCoords, Color color,int toolSize, ToolType tool)
{
    if (toolSize < 1) return null;
    Layer cLayer = layer;

    _oldBitmap = new WriteableBitmap(layer.LayerBitmap);
    _oldImage = layer.LayerImage;
    _oldImage.Source = _oldBitmap;

    switch (tool)
    {
        case ToolType.Pen:
            cLayer.LayerBitmap = DrawPixel(cLayer.LayerBitmap, startingCoords, toolSize,color);
            break;
        case ToolType.Bucket:
            cLayer.LayerBitmap = FloodFill(cLayer.LayerBitmap, startingCoords, color);
            break;
        case ToolType.Line:
            if (_toolIsExecuting == false)
            {
                LineAsync(cLayer, startingCoords, color, toolSize);
            }
            break;
        case ToolType.Circle:
            if(_toolIsExecuting == false)
            {
                CircleAsync(cLayer, startingCoords, color);
            }
            break;
        case ToolType.Rectangle:
            if(_toolIsExecuting == false)
            {
                RectangleAsync(cLayer, startingCoords, color);
            }
            break;              
        case ToolType.Earser:
            cLayer.LayerBitmap = DrawPixel(cLayer.LayerBitmap, startingCoords, toolSize, Colors.Transparent);
            break;
        case ToolType.Lighten:
            if(Mouse.LeftButton == MouseButtonState.Pressed)
            {
                cLayer.LayerBitmap = Lighten(cLayer.LayerBitmap, startingCoords);
            }
            else if(Mouse.RightButton == MouseButtonState.Pressed)
            {
                cLayer.LayerBitmap = Darken(cLayer.LayerBitmap, startingCoords);
            }
            break;
        default:
            break;
    }
    if (tool != ToolType.ColorPicker)
    {
        UndoManager.RecordChanges("ActiveLayer", new Layer(_oldBitmap, _oldImage), cLayer, string.Format("{0} Tool.", tool.ToString()));
    }

    return cLayer;
}

PS。没有复制位图就无法工作

1 个答案:

答案 0 :(得分:-1)

众所周知,位图的大小很大。您一直将旧状态添加到撤消堆栈中,以防止GC清除它们。这正是您不应该对图像等批量数据执行的操作。

我认为您只是无意中举例说明了不该做什么:)

解决方案:

停止保留大量未使用的图像!对撤消堆栈的大小设置一些合理的限制。或以不需要MiB精打细算的方式解决此问题。

尤其要记住的一件事是,内存中的图像是完全未压缩的。压缩仅适用于磁盘上的图像或通过网络传输的图像。为了显示或处理图像,每个高级步骤都必须撤消。它们占用的空间等于未压缩的位图图像的高度X宽度X颜色深度。