Search code examples
memorybitmapgdi+system.drawingpixel

Memory allocated with Marshal.AllocHGlobal is getting corrupted?


I need to create Bitmap objects with direct access to their pixel data.

LockBits is too slow for my needs - its no good for rapidly recreating (sometimes large) bitmaps.

So I have a custom FastBitmap object. It has a reference to a Bitmap object and an IntPtr that points to the bits in the bitmap.

The constructor looks like this:

public FastBitmap(int width, int height)
{
    unsafe
    {
        int pixelSize = Image.GetPixelFormatSize(PixelFormat.Format32bppArgb) / 8;
        _stride = width * pixelSize;

        int byteCount = _stride * height;

        _bits = Marshal.AllocHGlobal(byteCount);

        // Fill image with red for testing
        for (int i = 0; i < byteCount; i += 4)
        {
            byte* pixel = ((byte *)_bits) + i;
            pixel[0] = 0;
            pixel[1] = 0;
            pixel[2] = 255;
            pixel[3] = 255;

        }

        _bitmapObject = new Bitmap(width, height, _stride, PixelFormat.Format32bppArgb, _bits); // All bits in this bitmap are now directly modifiable without LockBits. 

    }
}

The allocated memory is freed in a cleanup function which is called by the deconstructor.

This works, but not for long. Somehow, without any further modification of the bits, the allocated memory gets corrupted which corrupts the bitmap. Sometimes, big parts of the bitmap are replaced by random pixels, other times the whole program crashes when I try to display it with Graphics.DrawImage - either one or the other, completely at random.


Solution

  • The reason the memory was being corrupted was because I was using Bitmap.Clone to copy the _bitmapObject after I was done with a FastBitmap.

    Bitmap.Clone does not make a new copy of the pixel data when called, or at least such is the case when you create a Bitmap with your own allocated data.

    Instead, cloning appears to use the exact same pixel data, which was problematic for me because I was freeing the pixel data memory after a clone operation, causing the cloned bitmap to become corrupt when the memory is used for other things.

    The first and current solution I have found as an alternative to Bitmap.Clone is to use:

    Bitmap clone = new Bitmap(bitmapToClone);

    which does copy the pixel data elsewhere, making it okay to free the old memory.

    There may be even better/faster ways to make a fully copied clone but this is a simple solution for now.