2012-02-16 73 views
0

我有点有点混乱有关.NET如何管理图片,我有以下的代码,建立一个管理的位图形成的非托管HBITMAP,perserving alpha通道。为什么GC正在失败,下面的代码片段

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; 
    } 

好吧,我知道,行GC.SuppressFinalize(bmp);有没有意义,但是当我删除了这一行,有时(每个4所或5调用)我得到以下异常:

尝试读取或写保护的内存。这通常是指示其他内存已损坏的 。

我怀疑是垃圾收集BMP对象被绘制回位图前,所以它试图访问由框架设置在位。如果我从来没有收集过它的bmp,​​但它会导致内存泄漏(从不收集bmp引用)。

你知道我怎么能解决这个问题呢?

回答

4

看一看该remakrs为Bitmap constructor you are using

调用方负责分配和释放由SCAN0参数指定的内存块。 但是,内存不应该被释放,直到相关的位图被释放。

这意味着你需要确保你保持记忆的底层块的保留状态bmpData指向直到GetBitmapFromHBitmap返回的Bitmap实例被释放后。

因为垃圾收集器检测到bmp不可达(未使用)你的问题引起,因此收集/最终确定这其中肯定释放内存在的块,但是即使你抑制你终结也仍称UnlockBits这意味着bmpData已经无效无论如何 - 它可能会在目前的工作,但完全放下那侥幸心理。为了使上面的代码正确的,你需要找到保持bmpData(通过扩展bmp)有效,只要返回Bitmap实例的机制是周围 - 即可能对您的应用程序显著变化。

或者看到Converting Bitmap PixelFormats in C#做(我觉得)你想达到的,同时避免所有这些问题完全是什么的一个完全不同的方式。