You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:35:21