如何调试运行数天后随机占用100% CPU的Go程序
Go应用偶发100% CPU占用排查方案
从两份栈trace定位问题根goroutine的方法
- 先筛选异常状态栈中所有状态为
running的goroutine:正常运行时running状态的goroutine数量和程序配置的GOMAXPROCS值基本一致,异常状态下如果某一类goroutine持续处于running态,就是核心排查对象,100% CPU占用90%以上都是这类goroutine陷入了无调度点的死循环导致。 - 对比两份栈的goroutine类型数量差异:如果某一类业务goroutine在异常栈中数量远高于正常栈,也需要重点排查是否出现了任务泄露叠加循环计算的问题。
- 从
running态goroutine的栈回溯中找自有业务代码的调用路径:跳过标准库、第三方依赖的栈顶函数,往下回溯到第一个项目下的包函数,该函数内的逻辑就是问题触发点。
针对pprof异常时无响应的补充排查手段
- 用系统级性能工具先定位占比最高的函数:执行
perf top -p <你的进程PID>,不需要程序做任何配合,即可直接看到用户态/内核态下CPU占用最高的函数符号,直接定位问题逻辑。 - 若怀疑是正则表达式回溯导致的问题,检查所有用户输入传入正则匹配的逻辑,确认是否存在滥用贪婪匹配、嵌套量词的正则规则,这类规则遇到特殊构造的输入会陷入无限回溯占满CPU。
- 检查所有循环逻辑:重点看有没有无任何IO、sleep、调度触发操作的空循环,或者循环退出条件永远无法满足的逻辑。
- 若使用的Go版本低于1.14,建议升级到1.14及以上版本,该版本引入了异步抢占机制,即使goroutine陷入无调度点的死循环,pprof也能正常采样不会卡死。
内容的提问来源于stack exchange,提问作者Lokesh
相关产品推荐
相关产品推荐

