当我使用using时为什么会出现内存不足的错误?

9
我有以下方法,可以将BitmapImage转换为System.Drawing.Bitmap:
public static Bitmap BitmapImageToBitmap(BitmapImage bitmapImage)
{
    Bitmap bitmap;

    using (var ms = new MemoryStream())
    {
        var encoder = new JpegBitmapEncoder();
        encoder.Frames.Add(BitmapFrame.Create(bitmapImage));
        encoder.Save(ms);

        bitmap = new Bitmap(ms);
    }

    return bitmap;
}

每当我尝试使用返回的Bitmap对象时,我都会收到以下错误消息:

发生OutOfMemoryException - 内存不足。

但是,每当我使用下面的代码替换它时:
public static Bitmap BitmapImageToBitmap(BitmapImage bitmapImage)
{
    var ms = new MemoryStream();

    var encoder = new JpegBitmapEncoder();
    encoder.Frames.Add(BitmapFrame.Create(bitmapImage));

    encoder.Save(ms);

    return new Bitmap(ms);
}

这个代码可以正常工作。然而,我相信我应该使用 using 关键字,因为 MemoryStream 对象实现了 IDisposable 接口。这里发生了什么?

2个回答

11

Bitmap的构造函数Bitmap Constructor (Stream)声明:

您必须在Bitmap的生命周期内保持流处于打开状态。

在您的情况下,当使用 using 语句时,流(被处理的对象)会自动释放资源,所以您的Bitmap对象变为无效。这并不是因为您分配了太多内存,而是因为Bitmap所指向的资源已经不再存在。


1
有什么推荐的解决方法吗?创建一个临时位图,复制它(使用new Bitmap(temp)temp.Clone()),然后处理掉这个临时位图? - CodesInChaos
@CodesInChaos:如果你将位图克隆到另一个实例中,并且仅在销毁流之后才使用它,那么可能(不确定)可以避免维护流的问题。 - Tigran

1

@Tigran所说的完全正确,我像这样实现了@CodesInChaos的解决方法:

public static Bitmap BitmapImageToBitmap(BitmapImage bitmapImage)
{
    Bitmap bitmap;

    using (var ms = new MemoryStream())
    {
        var encoder = new JpegBitmapEncoder();
        encoder.Frames.Add(BitmapFrame.Create(bitmapImage));
        encoder.Save(ms);

        using (var localBitmap = new Bitmap(ms))
        {
            bitmap = localBitmap.Clone(new Rectangle(0, 0, localBitmap.Width, localBitmap.Height),
                   PixelFormat.Format32bppArgb);  
        }
    }

    return bitmap;
}

不要忘记释放 localBitmap - CodesInChaos
JPEG部分很奇怪。为什么要将其保存为JPEG,然后再次加载呢?这样做的唯一效果就是降低质量。使用无损格式,例如.bmp作为序列化格式。 - CodesInChaos
我正在使用WPF,并且需要使用Aforge,因此我认为我需要将其转换为位图对象,使用Aforge完成必须的操作,然后再进行转换,这样做可以吗?实际上,我正在使用BMP文件,但我发现JpegBitmapEncoder也可以工作,还有一些其他编码器也可以,而且有些比其他的快,所以我正在尝试每一个来看哪个性能最佳。 - JMK
我的问题不在于这种转换(虽然有更好的方法),而主要在于你选择JPEG而不是无损格式(.bmp)。 - CodesInChaos
当我在测试时,我发现JpegBitmapEncoder是最快的编码器,但我没有意识到与较慢的BitmapEncoder相比会导致质量损失,这就是你所说的吗? - JMK
1
令人惊讶的是位图编码会更慢。位图编码不应该比内存复制慢太多。而且,我担心jpeg编码会导致质量损失。 - CodesInChaos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接