【问题标题】:Does Bitmap.LockBits "pin" a bitmap into memory?Bitmap.LockBits 是否将位图“固定”到内存中?
【发布时间】:2013-02-17 12:03:14
【问题描述】:

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

【问题讨论】:

  • 锁定后是否使用不安全代码操作位图?
  • 是的,我使用了不安全的代码。

标签: c# .net memory bitmap lockbits


【解决方案1】:

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

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

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

【讨论】:

  • 关于大型对象堆和超过 85k 的对象的部分是一个红鲱鱼,使这个答案变得更糟。在指针上使用GCHandle.Alloc 的建议也不好。
  • @BenVoigt 我已经把它变红了两次,不明白为什么它是红鲱鱼或不好。有了这个答案,我分享了我在类似案例stackoverflow.com/questions/14735520 中的过期时间(另请阅读 cmets )。所以请解释一下你的话。
  • 这个问题询问的是从Bitmap.LockBits() 得到的BitmapData.Scan0 指针。如果数据被移动,Bitmap 本身将失败,因此LockBits() 调用者没有任何理由尝试固定数据。如果缓冲区由Bitmap控制,这是通常的情况,它不会从GC堆中分配,所以它既不在分代堆上,也不在大对象堆上。
  • @BenVoigt 1) OP 已经明确假设 This is mostly because the bitmap has been moved in memory. 我的回答是,如果数据 > 85k,它不应该发生,但你称之为红鲱鱼。 2) And if the buffer is controlled by Bitmap, which is the usual case, it doesn't get allocated from GC heap。什么是 GC 堆?在 C# 中,数组是一个对象,并且对象总是在堆上分配,在 c# Bitmap 的情况下,它是一个托管堆。也许您认为 OP 分配 c 缓冲区并自己填充它,这只是您的假设,因为他可以从 c# 打开现有位图
  • 但是像素数据没有存储在任何对象中。它存储在非托管内存中,由 Windows(不是 C#)BITMAP 结构保存。这就是为什么LockBits 会返回带有像素数据的IntPtr,而不是byte[]
【解决方案2】:

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

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

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

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

完成后记得UnlockBits

【讨论】:

    猜你喜欢
    • 2011-11-02
    • 2012-05-21
    • 2012-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-05
    • 2011-10-23
    相关资源
    最近更新 更多