span是ref struct,生命周期绑定栈帧,不可作字段或用于async;memory是安全堆引用包装器,含object、index、length,可自由传递。

Memory<t></t> 和 Span<t></t> 是 .NET Core 2.1+ 引入的两个高性能内存抽象类型,本质都是“连续内存块的视图”,但一个能上堆、一个只能待在栈上——这是所有差异的起点。
为什么不能把 Span<t></t> 当字段或传给 async 方法?
因为它是 ref struct,编译器强制它生命周期绑定到当前栈帧。一旦方法返回、await 暂停、或赋值给类字段,就会报错:Cannot use variable 'xxx' in this context because it may be exposed outside of its scope。
- 错误示例:
class Processor { Span<byte> _buffer; } // 编译失败 - async 中直接用:
async Task ReadAsync(Span<byte> buf) { await Task.Delay(1); buf[0] = 1; } // 编译失败 - 正确替代:
Memory<byte></byte>可以自由作为字段、参数、返回值,内部用.Span属性临时转成Span<t></t>做操作
Memory<t></t> 的底层结构到底存了什么?
它不是指针,而是一个“安全的堆引用包装器”:包含一个 object(实际缓冲区引用)、int _index(偏移)、int _length(长度)。所以它本身是值类型,但背后可能指向堆数组、ArrayPool<t>.Rent()</t> 租来的缓冲区,甚至非托管内存。
大高朋团购系统是一套Groupon模式的开源团购程序,开发的一套网团购程序,系统采用ASP+ACCESS开发的团购程序,安装超简,功能超全面,在保留大高朋团购系统版权的前提下,允许所有用户免费使用。大高朋团购系统内置多种主流在线支付接口,所有网银用户均可无障碍支付;短信发送团购券和实物团购快递发货等。 二、为什么选择大高朋团购程序系统? 1.功能强大、细节完善 除了拥有主流团购网站功能,更特别支
-
Span<t></t>内部是ref T+length,真正是栈指针语义 -
Memory<t></t>的.Span属性每次调用都生成新Span<t></t>实例,不缓存、不共享,避免逃逸风险 - 它不持有原始数组强引用——如果源数组被 GC 回收,而你又没 Pin 或没管理好租约,
Memory<t></t>就会变成悬空视图(罕见但可能)
什么时候必须用 Memory<t></t>,什么时候死磕 Span<t></t>?
看生命周期和所有权:同步短时操作选 Span<t></t>;跨方法、异步、池化复用、需长期持有缓冲区引用,就用 Memory<t></t>。
- ✅ 必须用
Memory<t></t>:Stream.ReadAsync(Memory<byte>)</byte>、Socket.ReceiveAsync(Memory<byte>)</byte>、自定义IMemoryOwner<t></t>实现 - ✅ 推荐用
Span<t></t>:ReadOnlySpan<char>.IndexOf(':')</char>解析协议头、stackalloc byte[256]做本地缓冲、string.AsSpan().Trim()零分配字符串处理 - ⚠️ 常见误用:把
Memory<t></t>当作“更安全的Span<t></t>”无脑替换——它多一层间接、有微小开销,纯同步场景反而拖慢
最易忽略的一点:二者都不自动管理底层内存生命周期。用 ArrayPool<t>.Rent()</t> 得配 .Return(),用 MemoryManager<t></t> 得确保释放时机——Memory<t></t> 不是 GC 友好型“智能指针”,它只是让堆上持有可能性变得安全而已。









