C# access unmanaged array using Memory or ArraySegment?

C# access unmanaged array using Memory<T> or ArraySegment<T>?



With the introduction of Memory, Span and ArraySegment in C# 7.2, I was wondering if I could represent an unmanaged array as an enumerable object, that lives on the heap.


Memory


Span


ArraySegment



This latter requirement rules out Span, which basically implemented exactly what I wanted: e.g.


Span


unsafe { bytes = new Span<byte>((byte*)ptr + (index * Width), Width);



Is it possible to do the same with ArraySegment or Memory? Their constructors only accept byte, maybe there some way to trick C# into passing a byte* instead of byte?


ArraySegment


Memory


byte


byte*


byte





Why do you want to do this with a Span or Memory? You can Marshal.GlobalHAlloc and get an IntPtr to work with a set of unmanaged memory directly. You may be able to somehow translate that into a byte that can be passed into those objects. Are you wanting to create a new memory block to work on, or are you trying to access another process memory block?
– Ron Beyer
Sep 5 '18 at 17:27


Span


Memory


Marshal.GlobalHAlloc


IntPtr


byte





I'm using SkiaSharp to load images which I iterate over byte by byte. Currently I use a provided property which copies the data as byte to work with, but Skia also provides a native pointer to the unmanaged memory, which I want to explore because it saves me a memory copy.
– Red Riding Hood
Sep 5 '18 at 17:33



byte





@RonBeyer Memory<byte> is actually perfect for this...
– Marc Gravell
Sep 5 '18 at 18:49


Memory<byte>





@MarcGravell I agree now that I understand what the use case was, but I was unaware of the custom MemoryManager<T>, thanks!
– Ron Beyer
Sep 5 '18 at 18:50


MemoryManager<T>




1 Answer
1



Yes for Memory<T>, but you need to create your own MemoryManager<T>. Don't worry - this isn't as scary as it sounds - here's one I wrote earlier...:


Memory<T>


MemoryManager<T>


/// <summary>
/// A MemoryManager over a raw pointer
/// </summary>
/// <remarks>The pointer is assumed to be fully unmanaged, or externally pinned - no attempt will be made to pin this data</remarks>
public sealed unsafe class UnmanagedMemoryManager<T> : MemoryManager<T>
where T : unmanaged

private readonly T* _pointer;
private readonly int _length;

/// <summary>
/// Create a new UnmanagedMemoryManager instance at the given pointer and size
/// </summary>
/// <remarks>It is assumed that the span provided is already unmanaged or externally pinned</remarks>
public UnmanagedMemoryManager(Span<T> span)

fixed (T* ptr = &MemoryMarshal.GetReference(span))

_pointer = ptr;
_length = span.Length;


/// <summary>
/// Create a new UnmanagedMemoryManager instance at the given pointer and size
/// </summary>
public UnmanagedMemoryManager(T* pointer, int length)

if (length < 0) throw new ArgumentOutOfRangeException(nameof(length));
_pointer = pointer;
_length = length;

/// <summary>
/// Obtains a span that represents the region
/// </summary>
public override Span<T> GetSpan() => new Span<T>(_pointer, _length);

/// <summary>
/// Provides access to a pointer that represents the data (note: no actual pin occurs)
/// </summary>
public override MemoryHandle Pin(int elementIndex = 0)
elementIndex >= _length)
throw new ArgumentOutOfRangeException(nameof(elementIndex));
return new MemoryHandle(_pointer + elementIndex);

/// <summary>
/// Has no effect
/// </summary>
public override void Unpin()

/// <summary>
/// Releases all resources associated with this object
/// </summary>
protected override void Dispose(bool disposing)



Now you can use:


var mgr = new UnmanagedMemoryManager((byte*)ptr + (index * Width), Width);
Memory<byte> memory = mgr.Memory;



and memory can be stored on the heap.


memory



However, to minimize allocations you probably want to create a single UnmanagedMemoryManager<byte> that covers the entire region - once only - and then use .Slice(...) on the .Memory that represents the entire region. That way you have a single object and lots of slices (the slices are structs, not objects).


UnmanagedMemoryManager<byte>


.Slice(...)


.Memory



Note this implementation assumes that you're going to control the lifetime of the memory elsewhere - the Dispose() here does not attempt to release the memory via Marshal etc.


Dispose()


Marshal





UnmanagedMemoryManager - A legitimate use of a paradox if I've ever seen one.
– AaronLS
Sep 5 '18 at 18:52


UnmanagedMemoryManager





@AaronLS it does seem somewhat an oxymoron, I agree
– Marc Gravell
Sep 5 '18 at 18:53





@AaronLS Maybe it needs a manager because it's "unmanaged"? ;-)
– Ahmed Abdelhameed
Sep 5 '18 at 19:00





@MarcGravell This is amazing. Is there anything special I need to do to use this? I get The type or namespace name 'unmanaged' could not be found. Already imported System.Buffers and InteropServices
– Red Riding Hood
Sep 5 '18 at 19:42



The type or namespace name 'unmanaged' could not be found


System.Buffers


InteropServices





I removed the unmanaged interface and all the generics and it is now working.
– Red Riding Hood
Sep 5 '18 at 20:03


unmanaged



Thanks for contributing an answer to Stack Overflow!



But avoid



To learn more, see our tips on writing great answers.



Some of your past answers have not been well-received, and you're in danger of being blocked from answering.



Please pay close attention to the following guidance:



But avoid



To learn more, see our tips on writing great answers.



Required, but never shown



Required, but never shown




By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

𛂒𛀶,𛀽𛀑𛂀𛃧𛂓𛀙𛃆𛃑𛃷𛂟𛁡𛀢𛀟𛁤𛂽𛁕𛁪𛂟𛂯,𛁞𛂧𛀴𛁄𛁠𛁼𛂿𛀤 𛂘,𛁺𛂾𛃭𛃭𛃵𛀺,𛂣𛃍𛂖𛃶 𛀸𛃀𛂖𛁶𛁏𛁚 𛂢𛂞 𛁰𛂆𛀔,𛁸𛀽𛁓𛃋𛂇𛃧𛀧𛃣𛂐𛃇,𛂂𛃻𛃲𛁬𛃞𛀧𛃃𛀅 𛂭𛁠𛁡𛃇𛀷𛃓𛁥,𛁙𛁘𛁞𛃸𛁸𛃣𛁜,𛂛,𛃿,𛁯𛂘𛂌𛃛𛁱𛃌𛂈𛂇 𛁊𛃲,𛀕𛃴𛀜 𛀶𛂆𛀶𛃟𛂉𛀣,𛂐𛁞𛁾 𛁷𛂑𛁳𛂯𛀬𛃅,𛃶𛁼

Edmonton

Crossroads (UK TV series)