【问题标题】:ZXing still has a memory leak. Even after releasing the Global AllocZXing 仍然存在内存泄漏。即使在释放 Global Alloc 之后
【发布时间】:2012-05-15 18:09:36
【问题描述】:

在这篇文章中:Possible memory leak in Zxing's System.Drawing.Bitmap 提出了一个关于 ZXing 库中的内存泄漏的问题。我已经下载并使用免费分配的内存修改了库。我什至在适用的情况下引入了 using(){} 语句,但我仍然遇到内存泄漏。

我有一个怀疑。 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
}

}

【问题讨论】:

  • 只是出于兴趣,你是如何检查内存泄漏的?
  • 好吧,我没有。一段时间后,我对 Marshal.Copy 的内存不足

标签: c# xamarin.ios zxing


【解决方案1】:

您需要释放本机缓冲区,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 在 cmets 中的 try-finally 建议进行了更新

【讨论】:

  • 在整个代码周围添加一个try { } finally { Marshal.FreeHGlobal(rawData); } 是一个好主意,如果抛出异常,你会得到泄漏。
  • @Jonathan.Peppers +1 指向 finally 语句。这真的很有帮助。
  • 嗨,Rolf,已经这样做了。仍然在副本上内存不足。我还尽可能在其他对象上添加了使用。阅读下文如何改变结果
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-23
  • 2012-06-08
  • 2012-02-05
  • 2013-07-13
相关资源
最近更新 更多