string data = "Hello, World";// 想提取中间某个子串做处理string part = data.Substring(7, 5); // 得到 "World"看起来没问题,对吧?
但你知道吗?每次调用 Substring,其实都会创建一个新的字符串对象,悄悄在堆上“占地盘”。
如果这种操作频繁发生,尤其是处理大文本、网络数据流、文件读写时……内存压力蹭蹭涨,GC(垃圾回收)都得加班加点。
那有没有一种方式,能像“指针”一样,不复制数据,只指向原数据的某一段,又能保证类型安全、不越界?
答案就是:Span<t> 和它的“好兄弟”——Memory<t>!
今天我们就来聊聊这个在高性能场景中频频露脸的 Memory<t>,看看它到底怎么用,值不值得你把它加入日常工具箱。
Memory是何方神圣?
先说结论:Memory<t> 是什么?
简单粗暴地说:
Memory<t> 就是一个“可写的、支持任意内存来源的、安全的数据视图”。
它有点像 Span<t>,但更“耐久”——可以在 async/await 异步方法中传递,而 Span<t> 只能在栈上使用(不能跨方法异步传递)。
对比项 | Span | Memory |
存储位置 | 栈(stack)为主 | 可在堆上传递 |
是否可异步传递 | 不行 | 可以 |
性能 | 极致高效 | 高效,稍低一点 |
使用场景 | 同步高频操作 | 异步、缓存、流处理 |
你可以把它们想象成:
Span<t>:短跑冠军,爆发力强,但不能持久。
Memory<t>:马拉松选手,耐力好,能跑远路。
怎么用?
1. 创建一个 Memory<t>
// 从数组创建byte[] buffer = new byte[1024];Memory<byte> memory = buffer;// 也可以指定范围:从索引 100 开始,长度 200Memory<byte> subMemory = buffer.AsMemory(100, 200);---
2. 在方法间传递(支持异步!)
public async Task ProcessDataAsync(Memory<byte> data){ // 模拟异步处理 await Task.Delay(100); // 转成 Span 做高效操作 var span = data.Span; for (int i = 0; i < span.Length; i++) { span = (byte)(span + 1); // 简单加密一下 }}---
3. 和 Span<t> 配合使用(黄金搭档)
void ParseHeader(Span<byte> header){ // 高效解析,无额外分配 if (header.Length >= 4 && header[0] == 0x48) // 'H' { Console.WriteLine("Header valid!"); }}// 使用Memory<byte> mem = stackalloc byte[10]; // 或来自数组ParseHeader(mem.Span); // 转成 Span 传进去回到前面
回到前面,开头所说使用 Substring 截取字符串的例子,如果使用 Memory<t> 实现,该怎么做呢?
// 零拷贝字符串切片string text = "Hello, World!";ReadOnlyMemory<char> charMemory = text.AsMemory();// 如果需要Memory<char>,可以使用显式转换 // Memory<char> writableMemory = charMemory.ToArray().AsMemory();// 零拷贝字符串切片 ReadOnlyMemory<char> world = charMemory.Slice(7, 5);Console.WriteLine(world.ToString()); // 输出"World"运行程序,你将看到如下的效果:
看到没?整个过程没有创建新的字符串,内存复用,GC 压力小,性能自然就上去了。
总结
为什么 Memory<t> 能省内存?
因为它不复制数据,只是提供一个“视图”(View):
原始数据还在那儿(数组、native memory、stackalloc 等)
Memory<t> 只记录:从哪开始、多长、怎么访问
所有操作都在原数据上进行,零拷贝!
这就像你用“书签”标记一本书的某一页某一段,而不是把那段文字抄一遍。
最后
如果你觉得这篇文章对你有帮助,不妨点个赞支持一下!你的支持是我继续分享知识的动力。如果有任何疑问或需要进一步的帮助,欢迎随时留言。也可以加入微信公众号[DotNet技术匠] 社区,与其他热爱技术的同行一起交流心得,共同成长!
作者:小码编匠
出处:gitee.com/smallcore/DotNetCore
声明:网络内容,仅供学习,尊重版权,侵权速删,歉意致谢!
方便大家交流、资源共享和共同成长
纯技术交流群,需要加入的小伙伴请扫码,并备注【加群】
推荐阅读
觉得有收获?不妨分享让更多人受益
关注「DotNet技术匠」,共同提升技术实力
</t></t></char></char></t></t></t></t></t></t></t></t></t></t></t></t></t>
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!