死循环表现为CPU占用长期稳定在95%以上、线程处于RUNNABLE状态且无I/O等待;可通过资源监视器定位高稳占CPU线程,结合日志输出与循环入口调试确认。

当你发现电脑风扇持续狂转、系统响应迟钝,而任务管理器里某个进程CPU占用长期稳定在95%以上且数值几乎不波动,这极大概率不是临时计算高峰,而是程序陷入了死循环——它正在无休止地执行同一段逻辑,既不等待I/O,也不释放CPU。
观察进程状态与线程行为
打开任务管理器→“性能”选项卡→点击右下角“打开资源监视器”→切换到“CPU”标签页。找到目标进程,展开其线程列表,重点关注那些“CPU使用率”列数值长期高于80%、且每秒刷新时变化极小的线程。
这类线程通常处于RUNNABLE状态(Linux/Java中为R或runnable),而非S(sleeping)、D(uninterruptible sleep)或Z(zombie)。【RUNNABLE状态+高且稳定的CPU占用,是死循环最直接的运行时特征】。
如果多个线程都指向同一个方法名(如Worker.run()或Parser.parseLoop()),问题大概率就藏在这个共用逻辑里。
检查日志与循环体首行输出
方法一:在疑似循环入口处插入调试日志。
例如,在while (status == PENDING)或for (int i = 0; i 的第一行,添加<code>System.out.println("loop@" + i);或log.debug("iter: {}", i);。
这一步操作起来很简单,直接把日志语句加进去就行。但要注意:如果日志完全不输出,说明循环根本没进入;如果只输出一次就中断,说明卡在了循环体第一行之后的某条语句上(比如阻塞IO、锁等待、或无限递归)。
方法二:查看已有日志中该线程的最后几条记录。
搜索线程名(如Timer-0、AsyncTask#3)或traceId,确认它最后一次成功处理请求的时间点和输入参数。若所有卡住的请求都携带相同异常值(如timeout=0、id=null、state=INIT),这就是触发死循环的关键路径。
分析线程堆栈定位循环变量
第一步:用top -Hp <pid>找出占用最高的线程TID(十进制)。
第二步:将TID转为小写十六进制,例如printf "%x\n" 12345 → 3039。
第三步:导出完整线程栈:jstack -l <pid> > stack.log(Java)或pstack <pid> > stack.log(C/C++)。
第四步:在stack.log中搜索nid=0x3039,定位到对应线程块,只看状态为RUNNABLE的片段。
重点盯住堆栈最顶端的方法调用行,以及该方法源码中while/for语句附近的变量赋值——【循环变量是否在循环体内被更新?是否被意外重置?是否因浮点精度、整数除零、布尔短路导致条件永远为真?】。例如while (x != 0.1)在IEEE 754下几乎必然死循环。

















