异步加载BitmapSource映像时内存泄漏

时间:2022-08-26 21:35:28

I have a fair few images that I'm loading into a ListBox in my WPF application. Originally I was using GDI to resize the images (the originals take up far too much memory). That was fine, except they were taking about 400ms per image. Not so fine. So in search of another solution I found a method that uses TransformedBitmap (which inherits from BitmapSource). That's great, I thought, I can use that. Except I'm now getting memory leaks somewhere...

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

I'm loading the images asynchronously using a BackgroundWorker like so:

我正在使用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 just gets the Bitmap from the path and then converts to BitmapSource.

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

Here's the code snippet for ResizeBitmapSource:

这是ResizeBitmapSource的代码片段:

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;

That code is essentially the code from: http://rongchaua.net/blog/c-wpf-fast-image-resize/

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

Any ideas what could be causing the leak?

什么可能导致泄漏的想法?

edit: Here's the code for GetImageSource, as requested

编辑:这是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;
                }
            }

2 个解决方案

#1


4  

I think you misunderstood how the TransformedBitmap works. It holds onto a reference to the source bitmap, and transforms it in memory. Maybe you could encode the transformed bitmap into a memory stream, and read it right back out. I'm not sure how fast this would be, but you wouldn't then be holding on to the full sized bitmap.

我想你误解了TransformedBitmap是如何工作的。它保留对源位图的引用,并将其转换为内存。也许你可以将转换后的位图编码成一个内存流,然后立即将其读出来。我不确定这会有多快,但你不会坚持使用全尺寸的位图。

I found this blog post that returned a WriteableBitmap with the TransformedBitmap as the source. The WriteableBitmap will copy the pixel data to a memory buffer in the initializer, so it doesn't actually hold on to a reference to the TransformedBitmap, or the full sized image.

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

#2


1  

At a guess, from looking at your code you might need to dispose of the bitmap returned by the call to ImageUtils.GetImageSource(photo.FullName).

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

I have also noted on the blog you pointed out that the author has added an update (11th of March) about inserting a using statement to prevent memory leaks.

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

#1


4  

I think you misunderstood how the TransformedBitmap works. It holds onto a reference to the source bitmap, and transforms it in memory. Maybe you could encode the transformed bitmap into a memory stream, and read it right back out. I'm not sure how fast this would be, but you wouldn't then be holding on to the full sized bitmap.

我想你误解了TransformedBitmap是如何工作的。它保留对源位图的引用,并将其转换为内存。也许你可以将转换后的位图编码成一个内存流,然后立即将其读出来。我不确定这会有多快,但你不会坚持使用全尺寸的位图。

I found this blog post that returned a WriteableBitmap with the TransformedBitmap as the source. The WriteableBitmap will copy the pixel data to a memory buffer in the initializer, so it doesn't actually hold on to a reference to the TransformedBitmap, or the full sized image.

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

#2


1  

At a guess, from looking at your code you might need to dispose of the bitmap returned by the call to ImageUtils.GetImageSource(photo.FullName).

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

I have also noted on the blog you pointed out that the author has added an update (11th of March) about inserting a using statement to prevent memory leaks.

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