Span和Memory是C# 7.2引入的高性能内存抽象,Span为栈上安全的内存视图,零开销操作连续内存;Memory可跨作用域使用,支持async和字段存储,配合MemoryPool实现零拷贝与缓冲复用,显著降低GC压力,适用于高频数据处理场景。

Span
Span:栈上安全的“内存视图”
Span
- 支持从 T[]、String、stackalloc T[]、非托管指针等创建
- 切片(Slice)、索引、遍历都零开销,不产生新分配
- 常见用途:解析字节流、字符串切片、高性能序列化/反序列化
- 示例:Span
data = stackalloc byte[256]; data.Slice(0, 128);
Memory:可跨作用域的“托管内存视图”
Memory
- 比 Span
稍重(有虚方法调用开销),但保留了大部分零分配优势 - 配合 ReadOnlyMemory
使用更安全,防止意外写入 - 典型场景:ASP.net Core 中的 Request.Body.ReadAsync 接收 Memory
,Kestrel 直接复用缓冲池
为什么它们能提升性能?
传统方式(如 string.Substring、Array.copy)常触发堆分配或数据复制,而 Span/Memory 让你直接操作原始内存块:
- 避免不必要的数组分配(比如临时子串、中间 byte[])
- 绕过 GC 压力,尤其在高吞吐服务中效果显著
- 与 System.Buffers.MemoryPool
配合,实现高效缓冲区复用 - 支持 unsafe 操作(如指针转换),又保持类型安全边界
使用注意点
它们强大但需理解约束:
- Span
不能存储在堆对象中(编译器会报错),async 方法里慎用(推荐转 Memory ) - Memory
不一定对应托管数组——可能是 native 内存或池化内存,释放需按来源处理 - 跨线程传递需确保内存生命周期足够长,否则可能悬空
- 并非万能:简单逻辑用 string 或 List
更清晰,过度优化反而增加复杂度
基本上就这些。Span 和 Memory 不是语法糖,而是运行时与语言协同设计的底层能力,用对地方,性能提升立竿见影。