如何在不重新分配内存的情况下从Memory<byte>获取MemoryStream或其他Stream实例
无需拷贝内存从Memory获取Stream实例的实现方案
托管数组 backed 的
Memory<byte>场景(最常用)
绝大多数日常使用的Memory<byte>都基于托管数组分配,你可以通过MemoryMarshal.TryGetArray拿到对应的数组段,直接传给MemoryStream构造函数,该过程完全不会发生内存拷贝,Stream会直接操作原始数组的对应区间:Memory<byte> sourceMemory = GetYourMemoryInstance(); if (MemoryMarshal.TryGetArray(sourceMemory, out ArraySegment<byte> segment)) { // 直接使用原始数组构造MemoryStream,无内存拷贝 Stream stream = new MemoryStream(segment.Array, segment.Offset, segment.Count, writable: true); }该方法返回的Stream完全兼容标准
MemoryStream的所有用法,支持读写操作。非托管内存 backed 的
Memory<byte>或者跨版本通用场景
如果你的Memory<byte>来自非托管内存分配,无法拿到托管数组段,可以通过Pin住内存后构造UnmanagedMemoryStream实现零拷贝:unsafe { using var memoryHandle = sourceMemory.Pin(); // 直接基于内存指针构造Stream,无内存拷贝 Stream stream = new UnmanagedMemoryStream( (byte*)memoryHandle.Pointer, sourceMemory.Length, sourceMemory.Length, FileAccess.ReadWrite); }需要注意必须保持
memoryHandle的存活直到Stream使用完毕,避免内存被GC移动或者回收导致访问异常。如果是只读的ReadOnlyMemory<byte>,把FileAccess参数改为FileAccess.Read即可。低版本框架兼容场景(.NET Framework / .NET Core 2.x及以下)
你可以自定义继承自Stream的实现类,内部持有Memory<byte>实例,重写Read、Write、Seek、Length、Position等核心方法,直接操作Memory<byte>的Span属性,全程不需要分配额外的缓冲区,即可实现零拷贝的Stream封装。
内容的提问来源于stack exchange,提问作者Perfect28
相关产品推荐
相关产品推荐

