【问题标题】:Memory leak while asynchronously loading BitmapSource images异步加载 BitmapSource 图像时发生内存泄漏
【发布时间】:2010-03-11 19:48:36
【问题描述】:

我有一些图像要加载到我的 WPF 应用程序的 ListBox 中。最初我使用 GDI 来调整图像大小(原件占用太多内存)。这很好,除了他们每张图像需要大约 400 毫秒。不太好。因此,在寻找另一种解决方案时,我找到了一种使用 TransformedBitmap(继承自 BitmapSource)的方法。太好了,我想,我可以使用它。除了我现在在某个地方出现内存泄漏......

我正在使用 BackgroundWorker 异步加载图像,如下所示:

BitmapSource bs = ImageUtils.ResizeBitmapSource(ImageUtils.GetImageSource(photo.FullName));
                //BitmapSource bs = ImageUtils.GetImageSource(photo.FullName);
                bs.Freeze();

                this.dispatcher.Invoke(new Action(() => { photo.Source = bs; }));

GetImageSource 只是从路径中获取 Bitmap,然后转换为 BitmapSource。

这是 ResizeBitmapSource 的代码 sn-p:

const int thumbnailSize = 200;
        int width;
        int height;

        if (bs.Width > bs.Height)
        {
            width = thumbnailSize;
            height = (int)(bs.Height * thumbnailSize / bs.Width);
        }
        else
        {
            height = thumbnailSize;
            width = (int)(bs.Width * thumbnailSize / bs.Height);
        }

        BitmapSource tbBitmap = new TransformedBitmap(bs,
                                                           new ScaleTransform(width / bs.Width,
                                                                              height / bs.Height, 0, 0));

        return tbBitmap;

该代码本质上是以下代码: http://rongchaua.net/blog/c-wpf-fast-image-resize/

任何想法可能导致泄漏?

编辑: 这是 GetImageSource 的代码,根据要求

using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read))
            {
                using (var bmp = Image.FromStream(stream, false, false))
                {
                    // Use WPF to resize
                    var bitmapSource = ConvertBitmapToBitmapSource(bmp);
                    bitmapSource = ResizeBitmapSource(bitmapSource);
                    return bitmapSource;
                }
            }

【问题讨论】:

  • 您是如何诊断泄漏的?为什么你认为它在这段代码中,而不是在 GetImageSource() 中?
  • 我在 WPF 控件中使用的 BitmapSource 已正确调整大小,但查看进程使用的内存,它使用的内存与全尺寸图像一样。因此,沿着这条线的某个地方,全尺寸的 BitmapSource 并没有被删除。编辑:因为 GetImageSource 并没有真正改变。如果我选择使用 GDI 调整大小,那很好。但是当我使用这个 TransformedBitmap 方法调整大小时,它不起作用。
  • 你能不能尝试调用手动GC来查看内存是否被释放?如果不是,您很可能在某个地方有一个引用来保存内存。
  • 你能把你的代码发给ImageUtils.GetImageSource()吗?我怀疑那里发生了泄漏。
  • 我已将代码添加到 GetImageSource。 ConvertBitmapToBitmapSource() 的代码仅使用 Imaging.CreateBitmapSourceFromHBBitmap()。我以为可能是这样,但我不仅在原版中使用了这种方法,而且还删除了 Hbitmap IntPtr...

标签: c# wpf image memory-leaks bitmap


【解决方案1】:

我认为您误解了 TransformedBitmap 的工作原理。它保留对源位图的引用,并在内存中对其进行转换。也许您可以将转换后的位图编码为内存流,然后将其读回。我不确定这会有多快,但你不会坚持全尺寸的位图。

我发现这个blog post 返回了一个以 TransformedBitmap 作为源的 WriteableBitmap。 WriteableBitmap 会将像素数据复制到初始化程序中的内存缓冲区,因此它实际上不会保留对 TransformedBitmap 或全尺寸图像的引用。

【讨论】:

  • 好的,我想我理解你了。我会在早上试试,谢谢。
【解决方案2】:

猜测一下,通过查看您的代码,您可能需要处理调用 ImageUtils.GetImageSource(photo.FullName) 返回的位图。

我还在你指出的博客上注意到作者添加了关于插入 using 语句以防止内存泄漏的更新(3 月 11 日)。

【讨论】:

  • 是的,这是基于我添加的评论。但它似乎不起作用。并不是说他的代码不正确,但我的代码中有些东西导致它出错了……出错了……
猜你喜欢
  • 2016-08-10
  • 2011-11-05
  • 2017-01-27
  • 1970-01-01
  • 2018-10-02
  • 1970-01-01
  • 2014-12-01
  • 2017-05-10
  • 1970-01-01
相关资源
最近更新 更多