.NET图像调整大小的内存泄漏问题

5

我正在尝试批处理调整图像大小。当我使用.Net提供的类时,内存没有得到正确释放,因此会抛出OutOfMemoryException异常。我认为我已经正确使用了using语句。以下是代码:

    private static byte[] Resize(byte[] imageBytes, int width, int height)
    {
            using (var img = Image.FromStream(new MemoryStream(imageBytes)))
            {
                using (var outStream = new MemoryStream())
                {
                    double y = img.Height;
                    double x = img.Width;

                    double factor = 1;
                    if (width > 0)
                        factor = width / x;
                    else if (height > 0)
                        factor = height / y;

                    var imgOut = new Bitmap((int)(x * factor), (int)(y * factor));
                    var g = Graphics.FromImage(imgOut);
                    g.Clear(Color.White);
                    g.DrawImage(img, new Rectangle(0, 0, (int)(factor * x),
                                                   (int)(factor * y)),
                                new Rectangle(0, 0, (int)x, (int)y), GraphicsUnit.Pixel);

                    imgOut.Save(outStream, ImageFormat.Jpeg);

                    return outStream.ToArray();
                }
            }
      }

使用FreeImage库是这段代码的替代方案。当我使用FreeImage时,就没有内存问题了。使用FreeImage的代码:

   private static byte[] Resize(byte[] imageBytes, int width, int height)
   {
        var img = new FIBITMAP();
        var rescaled = new FIBITMAP();
        try
        {
            using (var inStream = new MemoryStream(imageBytes))
            {
                img = FreeImage.LoadFromStream(inStream);
                rescaled = FreeImage.Rescale(img, width, height, FREE_IMAGE_FILTER.FILTER_BICUBIC);

                using (var outStream = new MemoryStream())
                {
                    FreeImage.SaveToStream(rescaled, outStream, FREE_IMAGE_FORMAT.FIF_JPEG);
                    return outStream.ToArray();
                }
            }
        }
        finally
        {
            if (!img.IsNull)
                FreeImage.Unload(img);

            img.SetNull();

            if (!rescaled.IsNull)
                FreeImage.Unload(rescaled);

            rescaled.SetNull();
        }
   }

我的第一段代码有什么问题?

2
你没有在 Bitmap 上使用 Using...你还需要在 Graphics g 上使用 Using。 - Colin Smith
1
您没有释放 Graphics 对象 (var g = Graphics.FromImage(imgOut);)。 - Steve B
或者在 g 对象上 - 一个图形对象 - SteveLove
imgOutBitmap)和gGraphics)变量需要清理。 - ywm
感谢“FreeImage.Unload()” - 无法假设方法名称适用于处理。 - rock_walker
3个回答

5
我认为你的泄漏问题与以下两行代码有关:

我相信您的泄漏问题出在以下两行代码:

var imgOut = new Bitmap((int)(x * factor), (int)(y * factor));
var g = Graphics.FromImage(imgOut);

BitmapGraphics都实现了IDisposable接口,因此在使用完它们后应该释放资源。

我建议将它们都包装在using块中:

using(imgOut = new Bitmap((int)(x * factor), (int)(y * factor)))
{
    using(var g = Graphics.FromImage(imgOut))
    {
        //rest of code...
    }
}
这里是需要注意的GDI对象列表,如果您使用它们,请确保正确清除。

@AlexFilipovici:是的,我注意到了这些评论。我之前不知道需要处理它,所以我现在正在先进行调查。我似乎只在绘制事件处理程序中使用它,所以可能这就是我之前没有注意到问题的原因。 - musefan


0
更准确的方法:
private static byte[] Resize(byte[] imageBytes, int width, int height)
    {
        using (var imagestream = new MemoryStream(imageBytes))
        {
            using (var img = Image.FromStream(imagestream))
            {
                using (var outStream = new MemoryStream())
                {
                    double y = img.Height;
                    double x = img.Width;

                    double factor = 1;
                    if (width > 0)
                        factor = width / x;
                    else if (height > 0)
                        factor = height / y;

                    using (var imgOut = new Bitmap((int)(x * factor), (int)(y * factor)))
                    {
                        using (var g = Graphics.FromImage(imgOut))
                        {
                            g.Clear(Color.White);
                            g.DrawImage(img, new Rectangle(0, 0, (int)(factor * x),
                                                   (int)(factor * y)),
                                new Rectangle(0, 0, (int)x, (int)y), GraphicsUnit.Pixel);
                        }

                        imgOut.Save(outStream, ImageFormat.Jpeg);
                    }

                    return outStream.ToArray();
                }
            }
        }

 }

在分配和释放大对象(大小≥85000字节)时,您还需要非常小心......因为它们会保存在LOH(大对象堆)上,并且可能会导致其碎片化,从而比您预期更快地耗尽内存(如果遇到此问题,有各种技术可以解决它)。


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