I am wrapping a shared object library (FFTW) in .NET Core using P/Invoke. FFTW needs to allocate memory potentially aligned on particular boundaries, so I need to use its memory allocation routine. Ideally, I would like to avoid creating a separate chunk of memory in a managed array and copying the data across on every use. Ideally, the array is created to point to the already allocated memory. Is this possible, or should I give up and take the performance hit of a copy?
1 Answer
No, you can't create an array that points to unmanaged memory that has been allocated by an external memory manager. You can, however, create a Span<T> or a Memory<T> that does, which give you a very similar API and means you don't need unsafe at any point afterwards. Note that to be able to store it anywhere, it needs to be a Memory<T> (Span<T> is a ref struct) - but a Memory<T> is essentially just an on-demand span provider - when you want the span, call .Span on your Memory<T>.
Now; there isn't a Memory<T> for dealing with raw pointers that ships out of the box, but it is simple to write one. Or you can just use this one I wrote earlier (a MemoryManager<T> is an abstraction that can be used to implement custom Memory<T> instances, which can then provide a Span<T> when needed).
Usage:
int* ptr = ...
int len = ...
var memory = new UnmanagedMemoryManager<int>(ptr, len).Memory;
// (I should probably add a helper method for that!)
which gives you a Memory<int> that you can store in fields etc; then to work with it, you want the span:
var span = _memory.Span;
span[42] = 119; // etc
You can also do things like coerced type conversions over spans, allowing them to do most of the same things pointers can do (i.e. in the same way that you can force an int* to be a byte*, you can convert a Span<int> into a Span<byte> over the same memory - not a copy).
unsafecode. But, it has some drawbacks, and depending on how you want to expose the library, you can also useIntPtreverywhere and useMarshalclass helpers. Or use copy and measure if it's really a problem. Difficult to say w/o some end-to-end code (library + caller) sample that you envision.Memory<T>/Span<T>- which explicitly by design unifies the memory model between arrays and pointers