为何Span性能比Memory高出10倍?附基准测试代码与结果
为何Span的性能比Memory高出10倍?
基准测试代码
private byte[] _data; [Benchmark()] public void SpanTest() { var temp = _data.AsSpan(); var length = BitConverter.ToInt32(temp.Slice(0, 4)); var buffData = temp.Slice(4, length); var s = buffData[0]; } [Benchmark()] public async Task MemoryTest() { var temp = _data.AsMemory(); var length = BitConverter.ToInt32(temp.Slice(0, 4).Span); var buffData = temp.Slice(4, length); var s = buffData.Span[0]; }
基准测试结果

问题
我无法理解为何Span的性能比Memory高出10倍。在我看来,Span分配在栈上但指向堆中的数据(我的场景中),而Memory分配在堆上,这是我能看到的唯一区别。我的问题是:为何Span如此之快?我了解过ref struct,但不明白它的工作原理。
解答
1. Span是栈分配的ref struct,无堆开销
SpanSlice也会生成新的堆对象——这些堆分配和实例化本身就会带来额外性能损耗。
2. 避免间接寻址的额外开销
访问Memory.Span属性,这一步需要从堆上的Memory
3. 编译器的特殊优化
ref struct有严格约束(不能装箱、不能被捕获到闭包、不能跨await/async边界),编译器可以对Span
回到你的测试代码:
SpanTest全程在栈上完成:AsSpan()生成栈上Span,Slice仅修改栈上的偏移和长度,索引访问直接通过栈指针计算内存地址,无堆交互。MemoryTest中AsMemory()和两次Slice都会创建堆对象,每次访问.Span都要从堆读取数据,这些额外步骤叠加后,就造成了10倍的性能差距。
内容的提问来源于stack exchange,提问作者mazda3301
相关产品推荐
相关产品推荐

