Как я могу привязать массив байтов?
Я хочу связать массив байтов длиной 10 мегабайт, чтобы на нем мог работать управляемый и неуправляемый код.
Мой сценарий заключается в том, что у меня есть неуправляемый драйвер, который считывает некоторые данные с устройства и записывает его в большой массив, и управляемое приложение просто считывает эти данные.
Что-то вроде этого:
byte[] dataArray = new byte[10*1024*1024];
Я хочу привязать dataArray так, чтобы GC не двигал его.
Что происходит, когда я просто запускаю приложение, я получаю DataAbortApplication, и после прочтения в Интернете выяснилось, что я должен привязать dataArray
, чтобы избежать этой ошибки.
Как/что мне делать?
Ответы
Ответ 1
Есть два способа сделать это. Первый заключается в использовании оператора fixed
:
unsafe void UsingFixed()
{
var dataArray = new byte[10*1024*1024];
fixed (byte* array = dataArray)
{
// array is pinned until the end of the 'fixed' block
}
}
Однако, похоже, вы хотите, чтобы массив был закреплен в течение более длительного периода времени. Вы можете использовать GCHandle, чтобы выполнить следующее:
void UsingGCHandles()
{
var dataArray = new byte[10*1024*1024];
var handle = GCHandle.Alloc(dataArray, GCHandleType.Pinned);
// retrieve a raw pointer to pass to the native code:
IntPtr ptr = handle.ToIntPtr();
// later, possibly in some other method:
handle.Free();
}
Ответ 2
Вот класс, который можно использовать для привязки байтового массива до его размещения. Однако это похоже на сопоставленный файл с памятью, который будет более уместным в вашем сценарии.
public class PinnedBuffer : IDisposable
{
public GCHandle Handle { get; }
public byte[] Data { get; private set; }
public IntPtr Ptr
{
get
{
return Handle.AddrOfPinnedObject();
}
}
public PinnedBuffer(byte[] bytes)
{
Data = bytes;
Handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
Handle.Free();
Data = null;
}
}
}