所以我最终找到了一个增加内存消耗的问题。它是下面的类,由于某种原因不会收集垃圾。会出现什么问题? FastBitmap类的想法是锁定位图图像的位图数据一次,以避免在每次调用GetPixel / SetPixel时锁定/解锁。
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 :(得分:4)
几点:
您的班级可以访问固定数据。垃圾收集器通过在内存中移动结构来工作。只要位图锁定了它的位,垃圾收集器就无法对它做任何事情。
一旦你发布了FastBitmap,恐怕GDI +可能还会挂在数据位上。 GDI +是一个本地库,不与垃圾收集器交互。
您还需要释放(处置)GDI + Bitmap
。只需在subject.Dispose()
中致电Release
。
正如Mitchel所提到的,让你的FastBitmap实现IDisposable并重命名Release
来处理它会很不错。这将允许您在代码中使用using语句来确保确定性地释放数据。
答案 1 :(得分:2)
乍一看,我想说你想要在类上实现IDisposable接口,这样你就可以确保释放该类正在使用的资源。
答案 2 :(得分:0)
如果此类不是Garbage Collected,那么其他内容仍然会引用它。虽然内部数据可能是锁定它的原因,但我会首先查看其他地方。