我想固定一个10兆字节的字节数组,以便托管代码和非托管代码可以使用它。
我的方案是我有一个非托管驱动程序,它从设备读取一些数据并将其写入大数组,托管应用程序只读取该数据。
这样的事情:
byte[] dataArray = new byte[10*1024*1024];
我想固定dataArray,以便GC不会移动它。
当我运行应用程序时,实际上会发生什么,我得到一个DataAbortApplication,在网上阅读后我发现我应该固定dataArray
以避免此错误。
我该怎么做/应该做什么?
答案 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;
}
}
}