在 .NET 中,Span<T>
和 Memory<T>
旨在提高内存管理效率,减少不必要的分配,从而提升性能。
Span<T>
是一种 基于栈(stack-allocated) 的结构,允许高效操作连续的内存区域。
int[] numbers = { 1, 2, 3, 4, 5 };
Span<int> span = numbers;
span[0] = 10;
Console.WriteLine(numbers[0]);
// 输出: 10
在传统方法中,string.Substring()
会创建新的字符串对象,而 Span<T>
通过直接引用原始内存,避免额外的内存分配。
using System;
classProgram
{
static void Main()
{
string text = "Order1234: Processed";
// 使用 Span<T> 提取字符串片段,而不创建新字符串
ReadOnlySpan<char> span = text.AsSpan();
ReadOnlySpan<char> orderId = span.Slice(0, 10); // 提取 "Order1234"
ReadOnlySpan<char> status = span.Slice(12); // 提取 "Processed"
Console.WriteLine($"订单号: {orderId.ToString()}");
Console.WriteLine($"状态: {status.ToString()}");
}
}
优点:避免额外的内存分配,特别适用于大字符串的操作,提高性能。
✅ 不会分配新内存(减少 GC 压力)。
✅ 适用于数组、stackalloc
和非托管内存。
✅ 仅能用于同步方法,不支持 async/await
。
Memory<T>
和 Span<T>
类似,但 支持异步操作,因为它是 基于堆(heap-allocated) 的。
Memory<int> memory = new int[] { 1, 2, 3, 4, 5 };
Span<int> spanFromMemory = memory.Span;
spanFromMemory[0] = 20;
Console.WriteLine(memory.Span[0]);
// 输出: 20
当处理 大规模数据的异步任务(例如文件 I/O、网络流)时,Memory<T>
非常有用。
using System;
using System.IO;
using System.Threading.Tasks;
classProgram
{
static async Task Main()
{
byte[] buffer = newbyte[1024]; // 1 KB 缓冲区
Memory<byte> memoryBuffer = buffer;
using FileStream fileStream = new FileStream("largefile.txt", FileMode.Open, FileAccess.Read);
int bytesRead = await fileStream.ReadAsync(memoryBuffer);
Console.WriteLine($"读取字节数: {bytesRead}");
}
}
为什么选择 Memory?
✅ 支持异步方法(适用于 async/await
场景)。
✅ 不需要固定内存(不像 Span<T>
依赖栈或 stackalloc
)。
✅ 适合处理大数据集(如文件流、数据库缓冲区等)。
特性 | Span | Memory |
---|---|---|
内存分配 | 栈(Stack) | 堆(Heap) |
异步支持 | ❌ 不支持 | ✅ 支持 |
性能 | 🚀 更高 | 📉 稍低 |
📌 如果是同步代码,且追求高性能,使用 Span<T>
。
📌 如果需要异步处理(如文件 I/O、网络操作),使用 Memory<T>
。
Span<T>
和 Memory<T>
引入于 .NET Core 2.1,并支持以下版本:
Span<T>
**,但可以通过 System.Memory
NuGet 包实现部分支持。🔹 合理使用 Span<T>
和 Memory<T>
,可以让你的 .NET 代码更加高效! 🚀
本文使用 chatgpt辅助翻译。
作者:Dashrath Hapani,版权归原作者Dashrath Hapani所有
原文链接:csharp.com/article/understanding-spant-memoryt-for-low-level-memory-efficiency/