Why does the GC fail the next piece of code

I'm a little confused about how .NET manages images, I have the following code to create a managed raster form of an unmanaged HBitmap, while preserving the alpha channel.

public static Bitmap GetBitmapFromHBitmap(IntPtr nativeHBitmap) { Bitmap bmp = Bitmap.FromHbitmap(nativeHBitmap); if (Bitmap.GetPixelFormatSize(bmp.PixelFormat) < 32) return bmp; BitmapData bmpData; if (IsAlphaBitmap(bmp, out bmpData)) { // MY QUESTION IS RELATED TO THIS // IF CALL SUPPRESS_FINALIZE THE OBJECT // IT WILL WORK, OTHERWISE IT FAILS GC.SuppressFinalize(bmp); return new Bitmap( bmpData.Width, bmpData.Height, bmpData.Stride, PixelFormat.Format32bppArgb, bmpData.Scan0); } return bmp; } private static bool IsAlphaBitmap(Bitmap bmp, out BitmapData bmpData) { Rectangle bmpBounds = new Rectangle(0, 0, bmp.Width, bmp.Height); bmpData = bmp.LockBits(bmpBounds, ImageLockMode.ReadOnly, bmp.PixelFormat); try { return IsAlphaBitmap(bmpData); } finally { bmp.UnlockBits(bmpData); } } private static bool IsAlphaBitmap(BitmapData bmpData) { for (int y = 0; y <= bmpData.Height - 1; y++) { for (int x = 0; x <= bmpData.Width - 1; x++) { Color pixelColor = Color.FromArgb( Marshal.ReadInt32(bmpData.Scan0, (bmpData.Stride * y) + (4 * x))); if (pixelColor.A > 0 & pixelColor.A < 255) { return true; } } } return false; } 

Ok, I know that the line is GC.SuppressFinalize(bmp); it makes no sense, but when I delete this line, sometimes (every 4 or 5 calls), I get the following exception:

Attempted to read or write protected memory. It is often that other memory is corrupted.

I suspect that garbage collects the bmp object before the inverse bitmap is drawn, so it will try to access the bits that are located in the structure. If I never collect bmp, it works, but it causes a memory leak (the bmp link is never collected).

Do you know how I can solve this problem?

0
source share
1 answer

Take a look at remakrs for the bitmap constructor that you use

The responder is responsible for allocating and freeing the memory block specified by scan0. However, the memory should not be released until the corresponding bitmap is released.

This means that you need to make sure that you hold the base memory block pointed to by bmpData until the Bitmap instance returned by GetBitmapFromHBitmap .

Your problem is because the garbage collector found that bmp unavailable (not in use) and therefore collects / terminates it, which definitely frees up the base block of memory, however even if you suppress the finalizer that you still call UnlockBits , which means that bmpData no longer valid anyway - it may work at the moment, but it does not work completely. In order to correctly do the above code, you need to find a mechanism for storing bmpData (and the bmp extension), valid as long as the instance of the returned Bitmap instance is around - that is, perhaps a significant change for your application.

Alternatively, see Converting Bitmap PixelFormats to C # for a completely different way of doing (I think) what you want to achieve, completely avoiding all of these problems.

+4
source

All Articles