Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Safe use of Marshal.Copy from raw bitmap data to managed array

I posted a question not to long ago about how my program was essentially leaking memory: see here. I have now tracked it specifically to some code in which I copy the raw bytes of a Bitmap object into a managed array. The relevant code:

public class FastBitmap
{
    ...
    private byte[] rgbValues;
    private int height;
    private int width;
    private Bitmap image;

    public FastBitmap(Bitmap plainBitmap)
    {
        width = plainBitmap.Width;
        height = plainBitmap.Height;
        image = new Bitmap(plainBitmap);
        LockPixels(new Rectangle(0, 0, image.Width, image.Height));
    }

    private void LockPixels(Rectangle area)
    {
        if (locked)
            return;
        locked = true;
        BitmapData bitmapData = image.LockBits(area, ImageLockMode.ReadWrite,
                                PixelFormat.Format24bppRgb);
        IntPtr ptr = bitmapData.Scan0;
        int stride = bitmapData.Stride;
        int numBytes = image.Width * image.Height * 3;
        rgbValues = new byte[numBytes];
        for (int r = 0; r < image.Height; ++r)
        Marshal.Copy(new IntPtr((int)ptr + stride * r), 
                             rgbValues, image.Width * 3 * r, image.Width * 3);
    }
}

So thats all the extent of the code which is causing the memory not being recovered, and I imagine it has something to do with the Marshal.Copy() although I had assumed that since I was copying from a Bitmap (cleaned up on its own?) to a managed array, there was no issue.

So the question: Is it necessary to clean up the Bitmap object, either through an IDisposable interface, or something similar. What (if there is something) is inherently wrong with the use of Marshal.Copy() in this situation, and where can I clean up the issue?

Thank you

Just so you know I have tested the following code, to verify that it is indeed this causing the problem:

Bitmap bmp = new Bitmap(1000, 1000);
for (int n = 0; n < 100; ++n)
{
   FastBitmap fb = new FastBitmap(bmp);
}

At the start and end of this sequence the overall memory usage has increased by something like 320mb and doesn't go away, regardless of how long you wait.

like image 405
DeusAduro Avatar asked Jan 05 '10 09:01

DeusAduro


1 Answers

You have forgotten to call image.UnlockBits( bitmapData );

like image 103
Dan Byström Avatar answered Oct 27 '22 01:10

Dan Byström