如何将Memory<byte>复制到byte[]的指定偏移位置?
如何在无额外内存分配的情况下将Memory复制到byte[]的指定偏移?
问题描述
我在做异步网络IO开发时,使用Memory<byte>作为读取缓冲区,需要将其内容复制到一个预先定义的byte[](也就是代码里的Packet)的指定偏移位置。目前我的Append方法实现如下:
public bool Append(Memory<byte> buffer) { // Verify input data if (buffer.Length <= 0 || buffer.Length > PacketSize - Received) { // Debug.Assert(false); return false; } // Copy received data into packet at current offset // TODO : Avoid heap array allocation or iteration //Buffer.BlockCopy(buffer.ToArray(), 0, Packet, Received, buffer.Length); //private readonly byte[] Packet; for (int i = 0; i < buffer.Length; i ++) { Packet[Received + i] = buffer.Span[i]; } Received += buffer.Length; // If we have a header it must match if (HasHeader() && !DoesHeaderMatch()) { // Debug.Assert(false); return false; } return true; }
现在的问题是:我想找一个等效于Buffer.BlockCopy()的方法,但源数据是Memory<byte>或者它的Span<byte>类型,而且不想创建临时的栈或堆缓冲区——不管是调用buffer.ToArray()产生的堆分配,还是循环逐个赋值的低效操作,都想避免。有什么合适的解决思路吗?
解决方案
你可以直接利用.NET Core及以上版本提供的Span<T> API来实现无分配、高效的内存复制,这完全符合你的需求。修改后的复制逻辑如下:
// Copy received data into packet at current offset Span<byte> destination = Packet.AsSpan().Slice(Received, buffer.Length); Span<byte> source = buffer.Span; source.CopyTo(destination); Received += buffer.Length;
为什么这能解决问题?
- 无额外内存分配:
Memory<T>.Span和Array.AsSpan()都是直接创建内存的视图,不会在堆上分配新的数组;Slice方法也只是调整视图的起始位置和长度,同样没有分配。 - 高效复制:
Span<T>.CopyTo底层会根据目标和源的内存情况,自动选择最优的复制方式(比如利用硬件的批量复制指令),效率和Buffer.BlockCopy不相上下,甚至在某些场景下更优。 - 代码简洁:相比循环赋值,这段代码更易读,也更符合现代.NET的内存操作习惯。
你可以把这段代码替换掉原来的循环或者注释掉的Buffer.BlockCopy部分,就能实现无分配的高效数据复制了。
内容的提问来源于stack exchange,提问作者PieterV
相关产品推荐
相关产品推荐

