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();
        }
   }

私の最初のコードには何がありませんか?

4

2 に答える 2

5

あなたのリークは次の2行にあると思います:

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

両方ともBitmap実装GraphicsするIDisposableため、使用が終了したら破棄する必要があります。

using両方をブロックでラップすることをお勧めします。

using(imgOut = new Bitmap((int)(x * factor), (int)(y * factor)))
{
    using(var g = Graphics.FromImage(imgOut))
    {
        //rest of code...
    }
}

注意すべきGDI オブジェクトのリストを次に示します。これらを使用する場合は、適切にクリーンアップしてください。

于 2013-07-23T09:58:41.857 に答える
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 (Large Object Heap) に移行し、断片化してメモリ不足になる可能性があるためです。ご想像のとおりです (その問題に遭遇した場合、それを回避するためのさまざまな手法があります)。

于 2013-07-23T10:01:01.390 に答える