2012-04-11 55 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