我为了“即取即弃”白白分配了 7.8 MB 的字符串键
来源:dev.to — 2026-08-04
📋 概述
一次性能剖析把作者带到了一条他从未怀疑过的代码路径:一个请求处理器读取由空格分隔的 token 流,并对每个 token 做字典查询求和。逻辑正确也无趣,问题在于热循环里 7.8 MB 的字符串分配——每个被切出来的 token 都变成了独立的小字符串对象,仅仅为了交给 Dictionary.TryGetValue 做一次查询,随即被丢弃。他用 .NET 10 实测:20 万个 token 约 1.5 MB 输入,产出 7.5 MB 的垃圾,而这些清理开销最终会记到别的高延迟请求头上。自 .NET 9 起,Dictionary 支持用 ReadOnlySpan 做“备用查找”,从而免去这些分配。
🔑 核心要点
- 每个 Substring 切出的 token 都成为独立字符串,只为一次字典查询即被丢弃
- 实测 200,000 个 token 白白产生约 7.5 MB 垃圾,占 20 万次调用的热路径
- 垃圾回收的账单会记到别的请求延迟上,这也是此类问题难以定位的原因
- 自 .NET 9 起用 ReadOnlySpan<char> 备用查找,可免去每次查询的分配
💡 金句
Seven and a half megabytes of keys, none of which outlived a single if.
👍 0
👎 0
← 返回 Dev.to 首页