2009-11-24 108 views
2

所以我终于找到了一个问题,随着内存消耗的增长。这是下面的类,由于某种原因,不会收集垃圾。会有什么问题? FastBitmap类的想法是一次锁定位图图像的位图数据,以避免在每次调用GetPixel/SetPixel时锁定/解锁。为什么FastBitmap无法收集垃圾?

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

编辑

这里它是如何得到妥善收集真实..

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

你一定要读这个问题,特别注意“DO”和“DO NOT”部分:http://stackoverflow.com/questions/881473/why-catch-and-rethrow-exception-in-c – 2009-11-24 15:23:14

+0

您的Dispose方法有点复杂。为什么反弹到Dispose(布尔)?为什么要调用GC.SuppressFinalize?这些都没有必要,并会在1周内让你感到困惑。把事情简单化! – 2009-11-24 16:08:53

回答

4

有几点:

  • 你的班级组织访问固定数据。垃圾收集器通过在内存中移动结构来工作。只要位图锁定了它的位,垃圾收集器就无法对它做任何事情。

  • 一旦你释放了FastBitmap,我恐怕GDI +可能仍然挂在数据位上。 GDI +是不与垃圾收集器交互的本地库。

  • 您还需要释放(处置)GDI + Bitmap。请致电Release致电subject.Dispose()

正如米切尔提到,这将是很好,让您的FastBitmap实现IDisposable,并重新命名Release处置。这将允许您在代码中使用语句来确保数据是确定性释放的。

2

乍一看,我会说,你要考虑实施的类IDisposable接口这样您就可以确保释放课程使用的资源。

0

如果这个类没有被垃圾收集,那么其他东西仍然有一个引用它。虽然内部数据可能是锁定的内容,但我会先看看别处。