代码之家  ›  专栏  ›  技术社区  ›  DeusAduro

安全使用marshal.copy从原始位图数据复制到托管数组

  •  6
  • DeusAduro  · 技术社区  · 15 年前

    不久前,我发布了一个关于我的程序实际上是如何泄漏内存的问题:请参见 here . 现在,我专门跟踪了一些代码,在这些代码中,我将位图对象的原始字节复制到托管数组中。相关规范:

    public class FastBitmap
    {
        ...
        private byte[] rgbValues;
        private int height;
        private int width;
        private Bitmap image;
    
        public FastBitmap(Bitmap plainBitmap)
        {
            width = plainBitmap.Width;
            height = plainBitmap.Height;
            image = new Bitmap(plainBitmap);
            LockPixels(new Rectangle(0, 0, image.Width, image.Height));
        }
    
        private void LockPixels(Rectangle area)
        {
            if (locked)
                return;
            locked = true;
            BitmapData bitmapData = image.LockBits(area, ImageLockMode.ReadWrite,
                                    PixelFormat.Format24bppRgb);
            IntPtr ptr = bitmapData.Scan0;
            int stride = bitmapData.Stride;
            int numBytes = image.Width * image.Height * 3;
            rgbValues = new byte[numBytes];
            for (int r = 0; r < image.Height; ++r)
            Marshal.Copy(new IntPtr((int)ptr + stride * r), 
                                 rgbValues, image.Width * 3 * r, image.Width * 3);
        }
    }
    

    所以这就是导致内存无法恢复的所有代码范围,我认为它与marshal.copy()有关,尽管我假设从位图(自己清理?)复制之后。对于托管数组,没有问题。

    因此,问题是:是否需要通过IDisposable接口或类似的方式清理位图对象。在这种情况下使用marshal.copy()有什么内在的错误(如果有什么问题的话),在哪里可以清除这个问题?

    谢谢你

    正如您所知,我已经测试了以下代码,以验证这确实是导致问题的原因:

    Bitmap bmp = new Bitmap(1000, 1000);
    for (int n = 0; n < 100; ++n)
    {
       FastBitmap fb = new FastBitmap(bmp);
    }
    

    在这个序列的开始和结束时,总的内存使用量增加了320MB,并且不会消失,不管您等待了多长时间。

    1 回复  |  直到 15 年前
        1
  •  8
  •   Dan Byström    15 年前

    您忘记了调用image.unlockbits(bitmapdata);