2013-07-23 60 views
5

我正嘗試調整批處理作業中的圖像大小。當我使用.Net提供的類時,內存未正確釋放,因此引發OutOfMemoryException。我想我正確地使用了陳述。代碼如下:.net Image調整內存泄漏大小

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

您使用的不是使用位圖上的....你也想提出一個使用的圖形摹過。 –

+1

你沒有處理'Graphics'對象('var g = Graphics.FromImage(imgOut);') –

+0

或'g'對象 - 一個Graphics對象 – SteveLove

回答

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... 
    } 
} 

Here is a list of GDI objects保留一隻眼睛,一定要清除它們正確,如果你使用它們。

+0

也,'使用(var g = Graphics.FromImage(imgOut))'... –

+0

@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個字節)......因爲他們去蕙(大對象堆),並有可能將其分段,然後以超出預期的速度運行內存(如果遇到該問題,可以使用各種技術來解決問題)。