为什么FastBitmap没有收集垃圾?

时间:2009-11-24 15:08:29

标签: c# memory-management garbage-collection bitmap

所以我最终找到了一个增加内存消耗的问题。它是下面的类,由于某种原因不会收集垃圾。会出现什么问题? FastBitmap类的想法是锁定位图图像的位图数据一次,以避免在每次调用GetPixel / SetPixel时锁定/解锁。

    public unsafe class FastBitmap
    {
        private Bitmap subject;
        private int subject_width;
        private BitmapData bitmap_data = null;
        private Byte* p_base = null;

        public FastBitmap(Bitmap subject_bitmap)
        {
            this.subject = subject_bitmap;
            try
            {
                LockBitmap();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public void Release()
        {
            try
            {
                UnlockBitmap();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public Bitmap Bitmap
        {
            get { return subject; }
        }

        public void LockBitmap()
        {
            GraphicsUnit unit = GraphicsUnit.Pixel;
            RectangleF boundsF = subject.GetBounds(ref unit);
            Rectangle bounds = new Rectangle((int)boundsF.X, (int)boundsF.Y, (int)boundsF.Width, (int)boundsF.Height);
            subject_width = (int)boundsF.Width * sizeof(int);

            if (subject_width % 4 != 0)
            {
                subject_width = 4 * (subject_width / 4 + 1);
            }

            bitmap_data = subject.LockBits(bounds, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
            p_base = (Byte*)bitmap_data.Scan0.ToPointer();
        }

        private void UnlockBitmap()
        {
            if (bitmap_data == null) return;
            subject.UnlockBits(bitmap_data); bitmap_data = null; p_base = null;
        }
    }

修改

以下是如何妥善收集......

public unsafe class FastBitmap : IDisposable
{
    private Bitmap subject;
    private int subject_width;
    private BitmapData bitmap_data = null;
    private Byte* p_base = null;

    public FastBitmap(Bitmap subject_bitmap)
    {
        this.subject = subject_bitmap;
        try
        {
            LockBitmap();
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }

    public void Dispose()
    {
        Dispose(true);

        GC.SuppressFinalize(this);
    }

    private bool disposed = false;
    protected virtual void Dispose(bool disposing)
    {
        if (!this.disposed)
        {
            if (disposing)
            {
                UnlockBitmap();
                Bitmap.Dispose();
            }

            subject = null;
            bitmap_data = null;
            p_base = null;

            disposed = true;
        }
    }

    ~FastBitmap()
    {
        Dispose(false);
    }

    public Bitmap Bitmap
    {
        get { return subject; }
    }

    public void LockBitmap()
    {
        GraphicsUnit unit = GraphicsUnit.Pixel;
        RectangleF boundsF = subject.GetBounds(ref unit);
        Rectangle bounds = new Rectangle((int)boundsF.X, (int)boundsF.Y, (int)boundsF.Width, (int)boundsF.Height);
        subject_width = (int)boundsF.Width * sizeof(int);

        if (subject_width % 4 != 0)
        {
            subject_width = 4 * (subject_width / 4 + 1);
        }

        bitmap_data = subject.LockBits(bounds, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
        p_base = (Byte*)bitmap_data.Scan0.ToPointer();
    }

    public void UnlockBitmap()
    {
        if (bitmap_data == null) return;
        subject.UnlockBits(bitmap_data); bitmap_data = null; p_base = null;
    }
}

3 个答案:

答案 0 :(得分:4)

几点:

  • 您的班级可以访问固定数据。垃圾收集器通过在内存中移动结构来工作。只要位图锁定了它的位,垃圾收集器就无法对它做任何事情。

  • 一旦你发布了FastBitmap,恐怕GDI +可能还会挂在数据位上。 GDI +是一个本地库,不与垃圾收集器交互。

  • 您还需要释放(处置)GDI + Bitmap。只需在subject.Dispose()中致电Release

正如Mitchel所提到的,让你的FastBitmap实现IDisposable并重命名Release来处理它会很不错。这将允许您在代码中使用using语句来确保确定性地释放数据。

答案 1 :(得分:2)

乍一看,我想说你想要在类上实现IDisposable接口,这样你就可以确保释放该类正在使用的资源。

答案 2 :(得分:0)

如果此类不是Garbage Collected,那么其他内容仍然会引用它。虽然内部数据可能是锁定它的原因,但我会首先查看其他地方。