6

我最近经常使用锁定位图,并且不断收到“试图访问无效内存”错误。这主要是因为位图已在内存中移动。有些人使用GCHandle.Alloc()在 CLR 中分配内存并将其固定。做Bitmap.LockBits()同样的事情吗?我不明白“锁定”内存和“固定”内存之间的区别。如果有的话,你能解释一下术语和区别吗?

4

2 回答 2

10

GCHandle.Alloc是一种更通用的方法,它允许您为任何托管对象分配句柄并将其固定在内存中(或不固定)。固定内存可防止 GC 移动它,这在您必须将一些数据(例如数组)传递给非托管代码时特别有用。

GCHandle.Alloc不会帮助您以任何方式访问位图的数据,因为固定此对象只会阻止托管对象移动(位图对象)(并被垃圾收集)。

然而,位图是原生 GDI+BITMAP结构的包装器。它不会将数据保存在您必须固定的任何托管数组中,它只是管理 GDI+ 位图对象的本机句柄。因为这Bitmap.LockBits是告诉这个位图你有兴趣访问它的内存的一种方式,它只是一个函数的包装器GdipBitmapLockBits。因此,您需要调用它更多地与您使用 GDI+ 位图这一事实有关,而不是与您在使用 GC 的托管环境中工作这一事实有关。

一旦你使用过LockBits,你应该能够使用指针访问它的内存BitmapData.Scan0——它是第一个数据字节的地址。只要您不访问BitmapData.Scan0 + Height * Stride.

完成后请记住UnlockBits

于 2013-03-03T09:48:43.703 回答
0

在您的情况下,attempted to access invalid memory错误很可能是由您在代码的不安全部分中执行的无效内存分配引起的,例如分配的数组小于您尝试放入的像素数。

除非您的图像数据小于 85000 字节,否则也无需考虑固定对象,因为只有小于 85K 的对象才会在内存中移动。

另一个故事是,如果您将对象传递给非托管代码,例如在 c++ 库中以加快处理速度。在这种情况下,如果传递的图像超出范围并且将被垃圾收集,则您的异常很可能发生。在这种情况下,您可以使用 GCHandle.Alloc(imageArray,GCHandleType.Pinned);并在不再需要时调用 Free。

于 2013-03-03T10:14:03.597 回答