11 hours ago
- Span<T> 是一个ref结构体,提供对连续内存的类型安全、边界检查的视图,而不拥有或复制内存。
- 它可以包装数组、字符串、stackalloc块,以及通过MemoryMarshal管理的非托管内存。
- Span<T> 仅限于栈上使用,避免堆分配并确保GC重定位的安全性。
- 四种相关类型(Span<T>、ReadOnlySpan<T>、Memory<T>、ReadOnlyMemory<T>)覆盖了可变/只读和栈/堆两个维度。
- Memory<T> 是支持堆存储的对应类型,适用于异步场景,而Span<T> 用于同步场景。
- Span<T> 的ref struct限制在编译时强制生命周期管理,禁止字段存储、装箱、async/await和闭包。
- C# 13允许ref struct作为泛型类型参数约束,但未解除字段、闭包或async限制。
- 切片操作在不复制的情况下生成一个新的Span<T> 子范围,使用索引和范围语法。
- stackalloc与Span<T> 结合提供栈上分配的缓冲区,无GC压力,但仅限于当前栈帧,通常不超过1-2 KB。
- Span优先的解析通过在原始缓冲区上遍历索引来避免分配,仅在最终消费时才生成字符串或数字。
- SearchValues<T>(.NET 8+)优化了分词器和分隔符扫描中的重复IndexOfAny调用。
- Span优先的API设计以ReadOnlySpan<T> 作为规范重载,数组/字符串重载作为便利包装器。
- MemoryMarshal允许在类型边界间重新解释跨度,例如无需复制即可将字节缓冲区转换为结构跨度。
- 常见失败模式:在异步方法中使用Span<T>;修复方法是在异步层使用Memory<T>,在同步叶节点使用Span<T>。
- Span优先的解析相比基于字符串的解析在性能和内存方面有显著优势,零分配且更低延迟。
- 安全注意事项包括:编译器能捕获stackalloc跨度的直接逃逸,但无法捕获所有间接逃逸;切片边界检查虽然廉价但并非零成本。
- 以字符串为键的字典无法直接使用ReadOnlySpan<char> 而不调用ToString(),但.NET 9提供了GetAlternateLookup用于跨度键查询。
- Span<T> 未实现IEnumerable<T>,因此无法使用LINQ方法,需要手动实现。