使用WriteableBitmap.AddDirtyRect()时内存泄漏的解决方法

时间:2014-07-25 16:49:45

标签: c# wpf memory-leaks

在直接写入后备缓冲区并在单个锁定/解锁中多次使用AddDirtyRect函数时,WriteableBitmaps似乎存在内存泄漏。矩形需要在位图内定义不同的区域。当您尝试放弃WriteableBitmap时,内存将泄漏。

您可以通过将以下代码插入新的WPF应用程序来重新创建它。当应用程序启动时,调整窗口大小以创建新的WriteableBitmaps并观察内存上升。

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        Image m = new Image();
        m.Stretch = Stretch.Fill;
        this.Content = m;

        this.SizeChanged += OnSizeChanged;
    }

    private void OnSizeChanged(object sender, SizeChangedEventArgs args)
    {
        WriteableBitmap bm = new WriteableBitmap((int)args.NewSize.Width, (int)args.NewSize.Height, 96, 96, PixelFormats.Bgra32, null);

        bm.Lock();
        bm.AddDirtyRect(new Int32Rect(1, 1, 1, 1));
        bm.AddDirtyRect(new Int32Rect(2, 2, 1, 1));
        bm.Unlock();

        ((Image)this.Content).Source = bm;
    }
}

我们需要能够丢弃位图,以便保持相同的位图并重新使用它不是一种选择。我们也不能直接写入后备缓冲区,而是使用WritableBitmap.WritePixels(),但速度较慢,速度是个问题。

更新: 我已经测试了WritePixels方法,它泄漏了所有相同的内容。这可能是在不同地区过快地调用过多写入的问题。

1 个答案:

答案 0 :(得分:2)

我们已就此问题与Microsoft联系,但支持WPF的底层c ++库似乎存在问题。我们还没有承诺何时(或者如果)修复程序将会出现,但它仍然是.NET 4.5.1中的错误。

目前我们只有两种方法可以解决这个问题,它们是相互排斥的。你可以:

永远不会弄脏位图的任何子区域,只​​会弄脏整个位图

此方法的问题在于性能。您可以尝试通过缩小您的位图来抵消这种情况,但可能存在许多情况,这是不可能的。

永远不要丢弃您的位图

如果您要弄脏位图的多个子部分,那么除非您要关闭该应用程序,否则必须确保它永远不会被垃圾收集。这带来了它自身的一系列问题,因为在第一次创建位图时必须确保位图足够大。如果允许用户调整窗口大小,那么您必须使其适合整个桌面,但即使这样也会出现问题,因为用户可以更改其桌面分辨率或添加/删除监视器,这意味着您不得不泄漏内存或没有足够的位图来覆盖窗口的整个可能大小。

希望微软将来会发布一个针对此问题的解决方案,但同时对WriteableBitmap要非常小心,因为它很容易泄漏内存。