C#面试题更新 2026-08-05

请说明在 C# 中利用 Memory 和 Span 来提升集合操作性能的具体用法及其适用场景。

性能优化技术原理C#

考察说明

考查对 Span 和 Memory 在 C# 高性能编程中的应用,以及其与常规数组和集合的差异理解。

回答思路

  1. 【回答框架 1】Span<T> 是栈上分配的结构体,提供对连续内存的安全且高性能的切片访问,避免了创建数组副本和索引边界检查。Memory<T> 则是堆上分配的抽象,适用于异步方法和跨越 async 状态机的场景,可被视为一个可存储的 Span。
  2. 【回答框架 2】使用场景上,Span 适合同步方法内的局部处理,例如解析字符串、遍历数组片段;Memory 则适用于需要将数据传递给异步方法或存储在类字段中的情况。与集合相比,它们不分配堆对象(Span),且提供自动边界检查,避免缓冲区溢出,但要求底层数据必须是连续内存。
  3. 【回答框架 3】在具体操作中,可通过 span.Slice(start, length) 实现高效切片,或使用 stackalloc 分配栈上数组;也可通过 MemoryMarshal 与已有集合互操作。但需注意,Span 不能作为泛型参数、类字段、或者被装箱,且生命周期不能超过其引用的内存区域。
  4. 【回答框架 4】性能提升主要来自减少堆分配和数组拷贝,以及避免边界检查开销,但关键在于设计代码时优先考虑连续内存结构(如 T[]),并对热点代码做基准测试验证,以免过早优化。
  5. 【回答框架 5】当需要缓存切片或进行异步 I/O 时,使用 Memory 配合 MemoryPool 可重用缓冲区,降低 GC 压力,但需注意内存生命周期管理,确保在归还前不访问。
  6. 【关键点 1】Span 提供安全切片,避免拷贝和额外分配;Memory 支持异步场景。
  7. 【关键点 2】Span 不能存储在堆上或用于 async 方法;Memory 可作为字段持久化。
  8. 【关键点 3】使用 Slice 高效访问连续内存,优先使用数组而非 List 以利用 Span。
  9. 【关键点 4】性能收益源于减少分配和边界检查,需经基准验证。
  10. 【关键点 5】MemoryPool 用于缓冲复用,需遵循借用与归还约定。
  11. 【易错点 1】将 Span 存储在堆对象(如数组、字段)中,导致编译错误或运行时问题。
  12. 【易错点 2】在 async 方法中误用 Span,应改用 Memory 并将标识引用其数据。
  13. 【易错点 3】忽略底层数据连续性,试图对非连续集合使用 Span 而强制转换,引发数据错误。