如何固定一个字节数组?

时间:2014-04-23 20:40:33

标签: c# .net arrays

我想固定一个10兆字节的字节数组,以便托管代码和非托管代码可以使用它。

我的方案是我有一个非托管驱动程序,它从设备读取一些数据并将其写入大数组,托管应用程序只读取该数据。

这样的事情:

byte[] dataArray = new byte[10*1024*1024];

我想固定dataArray,以便GC不会移动它。

当我运行应用程序时,实际上会发生什么,我得到一个DataAbortApplication,在网上阅读后我发现我应该固定dataArray以避免此错误。

我该怎么做/应该做什么?

2 个答案:

答案 0 :(得分:23)

有两种方法可以做到这一点。第一种是使用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();
}

答案 1 :(得分:3)

这是一个可用于固定字节数组的类,直到被释放为止。但是,在您的场景中,内存映射文件听起来更合适。

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;
        }
    }
}