实验环境:cenos7
实验代码
模拟一段死循环的代码
/**
* 死循环Map测试
* 解决死循环问题:因为dataMap为空的时候,iterator.next()一直没有被调用到,就会导致死循环
*/
public Map<String, Object> deadIterator() {
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("onekey", new Object());
Map<String, Object> dataMap = new HashMap<>();
Iterator<String> iterator = paramMap.keySet().iterator();
while (iterator.hasNext()) {
System.out.println("iterator.hasNext()");
for (String keySet : dataMap.keySet()) {
System.out.println("for.dataMap.keySet()()");
if(iterator.next().equals(keySet)){
iterator.remove();
}
}
}
return paramMap;
}
实验步骤
在controller中,外部调用死循环的代码
/**
* 导致cpu飙高
* @return
*/
@RequestMapping("/deadIterator")
@ResponseBody
public String deadIterator() {
deadLockService.deadIterator();
return "deadIterator";
}
部署项目到linux环境并启动简单演示
java -Xmx32M -Xms32M -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./ -jar order-0.0.1-SNAPSHOT.jar &
调用接口:发现cpu飙高
排查演示
第一步:top命令,观察到pid 4906占用高
第二步:jps -l,果然是我们java应用对应pid=4906
第三步:导出线程栈信息,生成目录在本地,当然你也可以直接在服务器看
直接jstack 4906 即可。
jstack 4906 >> 4906.txt
线程文件导出
sz 4906.txt
打开分析:找一下没有可疑的信息,果真如图所示,定位到我们代码,导致排查完毕。
补充命令示例
top -Hp pid
printf "%x\n" 线程pid
jstack pid | grep 转换成16进制的数值 -A 30
jstack pid
sudo jsatck pid >> 789.txt