🔗 压测相关:2026年压测工具深度横评:k6 vs wrk vs hey vs vegeta vs oha — 五个工具逐个实测,选对工具性能调优才刚开始。
先讲个凌晨三点的故事
那天晚上我在群里被 @ 醒,说线上一个 .NET 服务响应从 50ms 涨到了 2 秒,内存还在匀速往上爬。我第一反应是 ssh 上去 top 一下,好家伙 CPU 直接 180%,GC 一秒好几次。
然后呢?然后我对着这个进程干瞪眼。Java 有 jstack、jmap,Python 有 py-spy,.NET 我居然不知道从哪下手。后来才把官方这套诊断工具链用明白——今天就把 dotnet-counters、dotnet-trace、dotnet-dump、dotnet-gcdump、dotnet-monitor 这五个家伙的实战体验一次说清楚。
五个工具分别是什么
1. dotnet-counters:先看全局,别瞎猜
这是我最先推荐的工具,没有之一。它就像 Linux 的 top,实时打印进程的性能计数器,但比 top 细得多:CPU 占用、托管堆大小、Gen0/1/2 的 GC 次数、异常抛出数、线程池队列长度,全都有。
dotnet-counters monitor -p 12345 --counters System.Runtime
输出长这样(大概意思):
CPU Usage (%) 62.3
Working Set (MB) 1024.5
GC Heap Size (MB) 512.7
Gen 0 GC Count 120
Gen 1 GC Count 30
Gen 2 GC Count 8
ThreadPool Queue Length 0
Exceptions Count 45
看到 Gen 2 GC 一分钟 8 次,心里就有数了——这是内存压力大的信号,不是 CPU 问题。工具开销极小(官方说 < 1% CPU),生产环境直接开没问题,这是它的最大优势。
优点:零侵入、开销低、上手零门槛,5 分钟就能看懂。缺点:只能看”现在发生了什么”,看不出”为什么发生”。
2. dotnet-trace:要火焰图,就找它
当你确定 CPU 高或者 GC 频繁,想定位到具体方法时,上 dotnet-trace。它采集事件级数据,类似 Linux 的 perf,支持直接导出火焰图。
dotnet-trace collect -p 12345 --format flamegraph
跑 30 秒,Ctrl+C 停掉,它会生成一个火焰图 HTML。我那次 CPU 180% 的排查,火焰图一出来直接锁定了罪魁祸首——一个日志库在热路径上做字符串拼接,占了 40% 的 CPU。之前猜了半小时”是不是 GC 问题”,火焰图 10 秒打脸。
优点:能精准定位热点方法、GC 分配点,出图直观。缺点:开销比 counters 大(一般 1-3% CPU),适合短时间采集;需要稍微看懂火焰图。
3. dotnet-dump:生产环境最安全的”事后分析”
很多故障是偶发的:你盯着的时候它好好的,你一走它就崩。这时候 dotnet-dump 是王牌——把进程快照抓下来,然后慢慢分析,不打扰线上。
dotnet-dump collect -p 12345
dotnet-dump analyze core_20260809_1.dmp
进入分析模式后,常用的 SOS 命令:
clrstack # 看托管线程栈
dumpheap -stat # 看堆上对象统计
gcroot <地址> # 看对象被谁引用
之前排查一个内存泄漏,就是 dump 下来后 dumpheap -stat 发现有一类缓存对象占了 3GB,再 gcroot 追到引用链,发现是 ConcurrentDictionary 只写不清理。这工具我在Python 内存泄漏排查那篇里说的思路一样——先看堆,再追引用,只是 .NET 这边用 SOS 命令。
优点:快照后离线分析,零风险;能查托管线程、堆对象、引用链。缺点:文件大(几 GB 常见),分析需要懂点 SOS 命令,学习曲线最陡。
4. dotnet-gcdump:只想查托管内存,用这个更轻
如果你确定问题就是内存(GC 堆涨、Gen2 频繁),不一定非要 dump 那么重的东西。dotnet-gcdump 只抓 GC 堆快照,文件小一个量级,打开也快。
dotnet-gcdump collect -p 12345
生成的 .gcdump 文件可以用 Visual Studio 打开,看对象类型分布、大对象堆、引用关系,非常直观。我查”哪个类型吃掉了内存”优先用这个,比 dump 快多了。这也呼应了之前聊过的C# Span 零分配优化——分配少了,gcdump 里自然干净。
优点:轻量、快、Visual Studio 可视化友好。缺点:只看得到托管堆,查不了线程栈和 CPU 热点。
5. dotnet-monitor:容器环境的神器
现在服务基本都跑在 Docker/K8s 里,上面那些工具都得进容器执行,命令可能没有,权限可能不够。dotnet-monitor 就是为这个场景生的:它作为 sidecar 或者直接嵌在应用里,暴露 HTTP 端点,远程就能抓 metrics、dump、gcdump、trace。
curl http://localhost:52325/metrics # Prometheus 格式指标
curl -X POST http://localhost:52325/dump # 远程抓 dump
curl -X POST http://localhost:52325/gcdump # 远程抓 gcdump
在 K8s 里配合 Prometheus 采集,你甚至能在 Grafana 上直接看 GC 指标。生产排障不用再”进容器敲命令”了。
优点:远程诊断、容器原生、指标可对接监控系统。缺点:多一个组件要运维;配置稍微复杂。
核心对比表
| 工具 | 解决什么问题 | 开销 | 上手难度 | 最适用场景 |
|---|---|---|---|---|
| dotnet-counters | 实时指标总览 | <1% CPU | ★☆☆☆☆ | 故障第一站,先看全局 |
| dotnet-trace | CPU 热点 / GC 事件 | 1-3% CPU | ★★☆☆☆ | 定位热点方法,出火焰图 |
| dotnet-dump | 线程栈 / 堆 / 引用链 | 抓取时暂停毫秒级 | ★★★★☆ | 偶发故障、内存泄漏深挖 |
| dotnet-gcdump | GC 堆对象分布 | 很轻 | ★★☆☆☆ | 内存问题快速定位类型 |
| dotnet-monitor | 容器远程诊断 | 低 | ★★★☆☆ | K8s / Docker 生产环境 |
我的实战决策路径
总结成一套固定流程,遇到 .NET 性能问题直接照着走:
- 先 counters 看全局:CPU 高?内存涨?GC 频繁?异常多?—— 定方向。
- CPU 高 → trace:30 秒火焰图,锁定热点方法。
- 内存涨 → gcdump:看 GC 堆里谁在膨胀,快速定位类型。
- 还查不清 → dump:线程栈 + 引用链,深挖根因。
- 容器环境 → monitor:全程远程操作,不碰容器。
这套流程和之前写过的C# LINQ 性能优化、C# Channel 高吞吐的排查思路是一脉相承的:先量化,再定位,最后优化。区别只是这次工具链齐了。
对了,图像化一点看这几个工具的分工:

常见问题(FAQ)
Q: 这些工具在生产环境直接跑安全吗?
dotnet-counters 和 dotnet-monitor 的指标采集开销极小,可以长期开。dotnet-trace 建议短时间(30秒-几分钟)采集。dotnet-dump 抓取瞬间进程会暂停几十毫秒到几百毫秒,对大多数服务可以接受,但大内存进程(10GB+)抓取前最好评估一下。
Q: 一定要装 Visual Studio 吗?
不用。除了 dotnet-gcdump 的可视化分析建议用 VS 外,其他工具都是命令行,dotnet-dump 用 SOS 命令分析,dotnet-trace 直接出火焰图 HTML,服务器上装个 dotnet-diagnostic-tools 的 dotnet tool 就行。
Q: .NET Framework 老项目能用吗?
dotnet-counters、dotnet-trace 等主要支持 .NET Core 3.0+。老 .NET Framework 项目可以退而求其次:用 procdump 抓 dump,配合 WinDbg 的 SOS 扩展分析,思路一样,命令略有差异。
Q: 工具在哪装?
都是 dotnet tool,一条命令的事:dotnet tool install -g dotnet-counters / dotnet-trace / dotnet-dump / dotnet-gcdump。dotnet-monitor 是独立的 NuGet 包或容器镜像。前提是目标机有 .NET SDK 或运行时。
总结
工具这东西,最怕的是”知道名字但不知道什么时候用”。我的建议很直接:先把 dotnet-counters 练熟,它是所有排查的第一站;再学会 dotnet-gcdump,内存问题十有八九够用;火焰图和 dump 是进阶,遇到棘手问题再上。
之前写Linux perf 火焰图和eBPF bpftrace的时候说过,排查能力是工程师的硬通货。这套 .NET 工具链补上之后,从系统层到应用层,你的武器库算是齐了。下次凌晨三点被叫醒,至少不用对着 top 干瞪眼了。