Как я могу привязать массив байтов?

Я хочу связать массив байтов длиной 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;
        }
    }
}