Span和Memory是C#7.2引入的高性能内存抽象,前者为栈上零分配视图,后者为可跨作用域的托管视图,二者均避免堆分配、减少GC压力,提升数据处理效率。
Span 和 Memory 是 C# 7.2 引入的核心高性能内存抽象类型,专为避免堆分配、减少 GC 压力、提升数据处理效率而设计。它们不是“替代数组”,而是更安全、更灵活的“内存视图”——能指向栈内存、堆数组、本机内存甚至只读数据,且全程不触发装箱或额外拷贝。
Span:栈友好的零分配切片工具
Span 是 ref-like 类型,只能在栈上声明(如局部变量、方法参数),不能作为字段、不能被装箱、不能跨 await 边界。它的价值在于对已有内存做“零成本切片”和“就地操作”。
- 从数组创建:Span span = array.AsSpan(); —— 不复制,只是引用起始地址+长度
- 切片操作:span.Slice(2, 5) —— O(1) 时间,返回新 Span,原数据不动
- 配合 stackalloc:Span buffer = stackalloc byte[256]; —— 栈上分配,无 GC 开销
- 写入字符串字节(UTF8):Utf8Encoder.Encode(buffer, “hello”, out int written);
Memory:可跨作用域的托管内存视图
Memory 是 Span 的“托管友好版”,可作为字段、参数、返回值,甚至用于 async 方法。它背后封装了 IMemoryOwner 或数组等资源,但本身不拥有内存。
- 从数组创建:Memory mem = array; 或 array.AsMemory()
- 获取可写 Span:Span span = mem.Span; —— 安全转为栈视图操作
- 异步场景示例:async Task ProcessAsync(Memory data) —— 调用方传入,方法内用 .Span 处理
- 注意:Memory 本身不可序列化,也不直接暴露指针,安全性高于裸指针
常见高性能组合模式
真实项目中,Span/Memory 往往和特定 API 协同使用,才能释放最大效能。