c# - 为什么 FastBitmap 没有被垃圾回收?

标签 c# memory-management garbage-collection bitmap

所以我终于找到了内存消耗不断增加的问题。这是下面的类,由于某种原因没有被垃圾收集。会有什么问题呢? 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;
    }
}

最佳答案

几点:

  • 您的类(class)拥有对固定数据的访问权限。垃圾收集器通过在内存中移动结构来工作。只要位图锁定了其位,垃圾收集器就无法对其执行任何操作。

  • 一旦您发布了 FastBitmap,恐怕 GDI+ 可能仍会卡在数据位上。 GDI+ 是一个 native 库,不与垃圾收集器交互。

  • 您还需要释放(处置)GDI+ 位图。只需在 Release 中调用 subject.Dispose() 即可。

正如 Mitchel 提到的,最好让 FastBitmap 实现 IDisposable 并重命名 Release 进行处置。这将允许您在代码中使用 using 语句来确保确定地释放数据。

关于c# - 为什么 FastBitmap 没有被垃圾回收?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1790678/

相关文章:

c# - 为什么 Visual Studio 2015 Intellisense 不显示任何类、方法等信息?

c++ - 如果将数据移动到不同的 block ,c++ realloc 函数是否对旧数据 block 应用删除操作?

memory-management - 在内存管理上下文中,静态堆栈和动态堆栈有什么区别

C# 垃圾收集器复活 Null Ref 异常

Java 大量的 char[],如何减少?

c# - 根据特定属性比较两个列表

c# - 如何在 Repeater 中应用样式

ios - 使用BOOL创建NSDictionary时收到EXC_BAD_ACCESS(Code = EXC_ARM_DA_ALIGN)

java - 使用超过 120GB RAM 的 Concurrent Mark Sweep 垃圾收集器

c# - OWIN 无法以 "The network location cannot be reached"开头