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

Span 和 Memory 是 C# 7.2 引入的高性能内存抽象类型,专为减少内存分配、避免复制、提升性能而设计,尤其适合底层操作、高频数据处理和零拷贝场景。
Span:栈上安全的“内存视图”
Span 是一个轻量级、仅栈分配(stack-only)的结构体,它不拥有数据,只指向一段连续内存(如数组、堆栈内存、非托管内存),并携带长度信息。它的关键特性是不能逃逸到堆上(比如不能作为字段、不能被 async 方法捕获),因此编译器能严格保证其生命周期安全。
- 支持从 T[]、string、stackalloc T[]、非托管指针等创建
- 切片(Slice)、索引、遍历都零开销,不产生新分配
- 常见用途:解析字节流、字符串切片、高性能序列化/反序列化
- 示例:Span data = stackalloc byte[256]; data.Slice(0, 128);
Memory:可跨作用域的“托管内存视图”
Memory 是 Span 的“可逃逸”兄弟,可以安全地作为字段、参数、返回值甚至用于 async 方法中。它内部包装了 Span 或其他内存源(如数组、ArraySegment),通过 MemoryManager 抽象统一管理生命周期。
- 比 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 不是语法糖,而是运行时与语言协同设计的底层能力,用对地方,性能提升立竿见影。
以上就是C# Span和Memory是什么 - 高性能内存操作的利器的详细内容,更多请关注php中文网其它相关文章!