English 中文(简体)
Why doesn t FastBitmap get garbage collected?
原标题:

So I ve finally located a problem I have with growing memory consumption. It s the class below, which for some reason doesn t get garbage collected. What would be the problem? The idea of the FastBitmap class is to lock the bitmap data of a bitmap image once to avoid locking/unlocking on each call to 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;
        }
    }

EDIT

Here s how it does get properly collected..

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;
    }
}
最佳回答

A couple points:

  • Your class hold access to pinned data. The garbage collector works by moving structures around in memory. So long as the bitmap has locked its bits, the garbage collector can t do anything with it.

  • Once you have Released the FastBitmap, I m afraid that GDI+ may still be hanging onto the bits of data. GDI+ is a native library that does not interact with the garbage collector.

  • You need to release (dispose of) the GDI+ Bitmap too. Just call subject.Dispose() in Release.

As Mitchel mentioned, it would be nice to make your FastBitmap implement IDisposable and rename Release to dispose. This will allow you to use using statements in your code to make sure that the data is freed deterministically.

问题回答

At a first glance i would say that you want to look into implementing the IDisposable interface on the class so that you can be sure to free up resources that are being used by the class.

If this class isn t being Garbage Collected, then something else still has a reference to it. While the internal data may be what is keeping it locked, I d look elsewhere first.





相关问题
Anyone feel like passing it forward?

I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...

NSArray s, Primitive types and Boxing Oh My!

I m pretty new to the Objective-C world and I have a long history with .net/C# so naturally I m inclined to use my C# wits. Now here s the question: I feel really inclined to create some type of ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

How to Use Ghostscript DLL to convert PDF to PDF/A

How to user GhostScript DLL to convert PDF to PDF/A. I know I kind of have to call the exported function of gsdll32.dll whose name is gsapi_init_with_args, but how do i pass the right arguments? BTW, ...

Linqy no matchy

Maybe it s something I m doing wrong. I m just learning Linq because I m bored. And so far so good. I made a little program and it basically just outputs all matches (foreach) into a label control. ...

热门标签