Reputation: 387
I want to pin an array of bytes which is 10 megabytes long so that managed and unmanaged code can work on it.
My scenario is that I have an unmanaged driver which reads some data from the device and writes it to the big array and the managed application just reads that data.
Something like this:
byte[] dataArray = new byte[10*1024*1024];
I want to pin dataArray so that GC does not move it.
What happens actually when I just run the application, I get a DataAbortApplication, and after reading on the internet I found out that I should pin the dataArray
to avoid this error.
How/what should I do?
Upvotes: 24
Views: 11413
Reputation: 30580
There are 2 ways to do this. The first is to use the fixed
statement:
unsafe void UsingFixed()
{
var dataArray = new byte[10*1024*1024];
fixed (byte* array = dataArray)
{
// array is pinned until the end of the 'fixed' block
}
}
However, it sounds like you want the array pinned for a longer period of time. You can use GCHandles to accomplish this:
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.AddrOfPinnedObject();
// later, possibly in some other method:
handle.Free();
}
Upvotes: 37
Reputation: 18223
Here is a class that can be used to pin a byte array until is disposed. However it sounds like a memory mapped file would be more appropriate in your scenario.
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;
}
}
}
Upvotes: 4