Bitmap.LockBits "прикрепляет" растровое изображение в память?

В последнее время я часто пользуюсь заблокированными растровыми изображениями и продолжаю получать сообщения об "попытках доступа к недопустимой памяти". Это в основном потому, что растровое изображение было перемещено в память. Некоторые люди, использующие GCHandle.Alloc() выделить память в CLR и закрепить ее. Есть ли Bitmap.LockBits() делать то же самое? Я не понимаю разницу между "блокировкой" памяти и "закреплением" памяти. Можете ли вы также объяснить терминологию и различия, если таковые имеются?

2 ответа

Решение

GCHandle.Alloc это более общий метод, который позволяет вам выделить дескриптор для любого управляемого объекта и закрепить его в памяти (или нет). Закрепление памяти не позволяет GC перемещать ее, что особенно полезно, когда вам нужно передать некоторые данные, например, массив, в неуправляемый код.

GCHandle.Alloc не поможет вам получить доступ к данным растрового изображения, потому что закрепление этого объекта просто предотвратит перемещение управляемого объекта (объект растрового изображения) (и сбор мусора).

Растровое изображение, однако, является оберткой вокруг нативных GDI+ BITMAP состав. Он не хранит данные в каком-либо управляемом массиве, который вам придется закрепить, он просто управляет собственным дескриптором объекта GDI+ bitmap. Из-за этого Bitmap.LockBits это способ сообщить этому растровому изображению, что вы заинтересованы в доступе к его памяти, и это просто оболочка GdipBitmapLockBits функция. Таким образом, ваша потребность вызывать его больше связана с тем, что вы работаете с растровыми изображениями GDI+, чем с тем, что вы работаете в управляемой среде с GC.

После того, как вы использовали LockBits Вы должны иметь возможность получить доступ к его памяти с помощью указателей через BitmapData.Scan0 - это адрес первого байта данных. У вас не должно быть проблем до тех пор, пока у вас нет доступа к памяти позади BitmapData.Scan0 + Height * Stride,

И помни UnlockBits когда вы сделали.

В вашем случае attempted to access invalid memory ошибка, скорее всего, вызвана неправильным выделением памяти, которое вы делаете в небезопасной части кода, например, выделенный массив меньше, чем количество пикселей, которые вы пытаетесь вставить в него.

Также нет необходимости думать о закреплении объектов, если только ваши данные изображения не имеют размер менее 85000 байт, поскольку только объекты размером менее 85 КБ будут перемещаться в памяти.

Другая история будет, если вы передадите объект в неуправляемый код, например, в библиотеку C++ для более быстрой обработки. В этом случае ваше исключение очень возможно, если переданное изображение выходит из области видимости и будет собирать мусор. В этом случае вы можете использовать GCHandle.Alloc(imageArray,GCHandleType.Pinned); и тогда звоните бесплатно, если вам это больше не нужно.

Другие вопросы по тегам