2012-04-11 84 views
1

在本文中:Possible memory leak in Zxing's System.Drawing.Bitmap有人問ZXing庫中的內存泄漏問題。我已經下載並修改了庫,並且沒有分配的內存。我甚至在適用的情況下使用了(){}語句,但我仍然遇到內存泄漏。ZXing仍然有內存泄漏。即使在發佈全球Alloc

我有一個懷疑。 Marshal.Copy可能做的更多,然後將數據從源複製到目標。複製後我是否也必須釋放目的地?

正如你可以在下面的代碼中看到的,我甚至試圖分配緩衝區只有一次,只有當請求一個大於前一個圖像的圖像重新分配時,但這並沒有解決問題。

問候 保羅

我改變代碼:

using System; 
using MonoTouch.UIKit; 
using MonoTouch.CoreGraphics; 
using System.Runtime.InteropServices; 
using System.Diagnostics; 

namespace System.Drawing 
{ 
public class Bitmap : IDisposable 
{ 
    byte[] pixelData = new byte[0]; 
    int width = 0; 
    int height = 0; 
    static IntPtr m_BufferPointer = default(IntPtr); 
    static int m_Size; 

    /// <summary> 
    /// Reallocs the buffer when it becomes too small 
    /// </summary> 
    private IntPtr ReallocBuffer(int size) 
    { 
     if(m_BufferPointer != default(IntPtr)) 
     { 
      if(m_Size < size) 
      { 
       Marshal.FreeHGlobal(m_BufferPointer); 
       m_BufferPointer = Marshal.AllocHGlobal(size); 
      } 
     } 
     else 
     { 
      m_BufferPointer = Marshal.AllocHGlobal(size); 
     } 

     m_Size = size; 

     return m_BufferPointer; 
    } 

    public Bitmap (UIImage image) 
    { 
     UIImage backingImage = image; 
     IntPtr rawData; 

     using (CGImage imageRef = backingImage.CGImage) 
     { 
      width = imageRef.Width; 
      height = imageRef.Height; 

      using (CGColorSpace colorSpace = CGColorSpace.CreateDeviceRGB()) 
      { 
       int size = height * width * 4; 
       rawData = ReallocBuffer(size); //Marshal.AllocHGlobal (height * width * 4); 

       using (CGContext context = new CGBitmapContext (rawData, width, height, 8, 4 * width, colorSpace, CGImageAlphaInfo.PremultipliedLast)) 
       { 
        context.DrawImage (new RectangleF (0.0f, 0.0f, (float)width, (float)height), imageRef); 

        pixelData = new byte[height * width * 4]; 

        Marshal.Copy (rawData, pixelData, 0, pixelData.Length); 
       } 
      } 
     } 
    } 

    private static int CountCalled; 
    private static int LastCountCalled = 20000000; //30411000; 

    public Color GetPixel (int x, int y) 
    { 
     try 
     {    
      CountCalled++; 

      if (CountCalled - LastCountCalled > 100000) 
      { 
       Debug.WriteLine (CountCalled); 
       LastCountCalled += 1000000; 
      } 

      byte bytesPerPixel = 4; 
      int bytesPerRow = width * bytesPerPixel; 
      int rowOffset = y * bytesPerRow; 
      int colOffset = x * bytesPerPixel; 
      int pixelDataLoc = rowOffset + colOffset; 

      Color ret = Color.FromArgb (pixelData [pixelDataLoc + 3], pixelData [pixelDataLoc + 0], pixelData [pixelDataLoc + 1], pixelData [pixelDataLoc + 2]); 
      return ret; 
     } 
     catch (Exception ex) 
     { 
      Console.WriteLine ("Req: {0}x{1}", x, y); 
      throw ex; 
     } 
    } 

    #region IDisposable implementation 
    public void Dispose() 
    { 
     pixelData = null; 
     GC.Collect(0); 
    } 
    #endregion 
} 

}

+0

只是出於興趣,你如何檢查內存泄漏? – Max 2012-04-12 14:43:28

+0

嗯,我不知道。在一段時間後,我在Marshal.Copy上遇到了內存不足 – 2012-05-15 09:54:58

回答

2

你需要釋放本地緩存,CGBitmapContext不會爲你做:

IntPtr rawData = Marshal.AllocHGlobal (height * width * 4); 

try { 
    using (CGContext context = new CGBitmapContext (rawData, width, height, 8, 4 * width, colorSpace, CGImageAlphaInfo.PremultipliedLast)) 
    { 
     context.DrawImage (new RectangleF (0.0f, 0.0f, (float)width, (float)height), imageRef); 

     pixelData = new byte[height * width * 4]; 

     Marshal.Copy (rawData, pixelData, 0, pixelData.Length); 
    } 
} finally { 
    Marshal.FreeHGlobal (rawData); 
} 

根據Jonathan.Peppers更新try-f在意見中的最新建議

+3

{try {} finally {Marshal.FreeHGlobal(rawData); }'在整個代碼周圍添加一個好主意,如果拋出異常,你會得到一個泄漏。 – jonathanpeppers 2012-04-11 12:20:14

+0

@ Jonathan.Peppers +1指向finally語句。這真的很有幫助。 – rekire 2012-04-11 18:03:23

+0

Hi Rolf,已經做到了。仍然在拷貝上的內存不足。我還在其他對象上添加了可能的地方。請閱讀下面的內容,如何改變結果 – 2012-05-15 10:13:15