1

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?

6
  • The easiest answer is: use unsafe code. But, it has some drawbacks, and depending on how you want to expose the library, you can also use IntPtr everywhere and use Marshal class 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. Commented Jul 28, 2018 at 6:08
  • You can't control the alignment of the managed array data at all, 4 in 32-bit mode and 8 in 64-bit mode. Also the reason that SIMD code in .NET is pretty limited. Not that much to worry about btw, the FT is a lot more expensive than the copying. Commented Jul 28, 2018 at 7:14
  • 1
    @SimonMourier no, I strongly disagree: the answer here is Memory<T> / Span<T> - which explicitly by design unifies the memory model between arrays and pointers Commented Jul 28, 2018 at 12:23
  • 1
    @MarcGravell - you're strongly right, but this is strongly quite recent (.NET core 2.1), and Microsoft hasn't strongly even finished the doc as of today: learn.microsoft.com/en-gb/dotnet/api/… Commented Jul 28, 2018 at 14:31
  • 1
    I have been for two years working at a company where we always seem to be on the bleeding edge of Microsoft's .NET related features, so I am used to bad docs and shifting technologies. This question is hobby project related, and yet I find myself again on the bleeding edge of .NET Core. Commented Jul 29, 2018 at 5:14

1 Answer 1

5

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).

Sign up to request clarification or add additional context in comments.

2 Comments

This looks like a very good answer. Thank you! I am going to try and test before I accept any answer.
Tested Span<T> and it accomplishes my goals. Thank you.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.