如果Bitmap从Marshal.AllocHGlobal获取原始数据,则内存泄漏?

时间:2010-12-25 22:25:06

标签: c# bitmap pinvoke marshalling

我不清楚原生互操作的机制。

假设我执行以下操作:

IntPtr nativeArray = Marshal.AllocHGlobal(stride * height);
someNativeCallToFillRawImageData(nativeArray, width, stride, height);
return new Bitmap(width, height, stride, PixelFormat.Format24bppRgb, nativeArray);

我分配的数组然后是位图的来源(它可以工作),但我不确定它的内存是否会被清除?

或者,我可以执行以下操作(通过更改DLLImport签名...本机方法最初定义为(unsigned char * buff)):

byte[] managedArray = new byte[stride * height];
someNativeCallToFillRawImageData(managedArray, width, stride, height);
fixed (byte* ptr = managedArray)
{
   return new Bitmap(width, height, stride, PixelFormat.Format24bppRgb, new IntPtr(ptr));
}

这也有效,但我并不清楚其中的区别。我也认为第一个变体更快,因为它不必跨越托管/非托管边界。

托管的Bitmap对象是否处理Scan0中的数据,即使它是由其他人分配的? bitmap.Dispose() - >在managedArray或nativeArray中分配内存会发生什么?

非常感谢你!

3 个答案:

答案 0 :(得分:2)

如果使用Marshal.AllocHGlobal并且位图从指针复制数据,则应使用Marshal.FreeHGlobal释放它。 我建议你在BitMap构造函数上阅读MSDN,看它是复制数据还是仅使用指针;如果它只是使用指针你必须等待释放它。

答案 1 :(得分:1)

我认为你不需要自己分配内存。创建一个具有所需大小的空位图,然后调用LockBits来访问原始像素数据:

Bitmap bmp = new Bitmap(width, height, PixelFormat.Format24bppRgb);
Rectangle rect = new Rectangle(width, height);
BitmapData data = null;
try
{
    data = bmp.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);
    someNativeCallToFillRawImageData(data.Scan0, data.Width, data.Stride, data.Height);
}
finally
{
    if (data != null)
        bmp.UnlockBits(data);
}

这样,内存由Bitmap对象处理,因此您无需担心。

答案 2 :(得分:1)

您应该在使用非托管资源(在您的情况下为nativeArray)的类中创建Dispose方法,并使用Marshal.FreeHGlobal(nativeArray )释放它。像这样:

if(nativeArray != IntPtr.Zero)
    Marshal.FreeHGlobal(nativeArray);

您有责任调用已创建的Dispose方法。