本文引用自:windows 排查javaWeb程序占用CPU过高问题(可追踪到问题代码所在行)_51CTO博客_windows java cpu过高排查
(https://blog.51cto.com/u_15964717/6059215)
坑1:cmd中运行【 jstack 16992 > d:/a.txt 】时提示:
'jstack' 不是内部或外部命令,也不是可运行的程序
或批处理文件。
原因是环境变量里没有JDK,cmd没找到jdk下的jstack这个命令
解决方法:用cd命令切换到jdk目录的bin中再执行这个命令。
坑2:cmd中运行【jstack 16992 > d:/a.txt】时提示:
16992: 拒绝访问。
我这里的原因是登录windows的账号没有权限。
解决方法:切换为administrator登录windows即可。
坑3:导致CPU占用100%的罪魁祸首 —— 最大的坑:
起因是 为了防止xss攻击,设置了过滤器,将提交的所有请求参数的值中的每个字符过滤一遍,一旦出现【 " ' < > 】这四个中的任意一个,则转义为实体字符。
原先的写法是:
static String escape(String str) {
if (str == null) {
return null;
} else {
String text = "";
char c;
// 转义特殊字符:" 34 ' 39 < 60 > 62
for (int i = 0; i < str.length(); i++) {
c = str.charAt(i);
if (c == 34 || c == 39 || c == 60 || c == 62) {
text = text + "&#" + (int) c + ";";
} else {
text = text + c;
}
}
return text;
}
}
这个逻辑看起来似乎没什么问题,并且也一直这样用了两年多。但没有问题的前提是请求字段的值不算太长。直到最近,业务新需求是【用base64字符串上传图片】。这里直接就引发问题了。base64字段的值非常长(照片大小500KB左右),每一次请求的长度都达到几百万,导致这个for循环半分钟才能完成。但是,在半分钟之内,此次循环还没结束,下一次请求又来了。频繁请求之下,CPU当然吃不消了,所以CPU占到了100%。
网上说CPU占到100%多数情况是出现了死循环,所以我写代码一般都会避免死循环。这个虽然不是死循环,但它产生了和死循环差不多的效果。
优化后的代码:
private static String escape(String str) {
if(str == null) {return null;}
str = str.replace("'", "'");
str = str.replace("\"", """);
str = str.replace("<", "<");
str = str.replace(">", ">");
return str;
}
这个问题耽误一天时间是小事,程序一直崩溃耽误客户使用是关键。
谨以此作个记录,给自己及各位网友的提醒:
写代码时要时刻注意死循环,固然很关键,但同样要注意是否有这种超大循环(百万次循环)的情况出现。尤其是在循环嵌套循环的时候,多层循环嵌套更要尤为注意。
另附:
在某些情况下,为了实现某种功能,部分代码必须反复执行不能停止,这时一般都会采用死循环的方式。死循环并非不能用,但一定要控制好。如果功能要求必须无限重复,循环次数无限大,那么这时就一定要控制好循环速率。哪怕只是最简单粗暴的方式:【Thread.sleep(毫秒数);】,也别让速度失控(一秒循环十万次)。否则一旦把CPU累趴下 干不动活了,那时程序恐怕也已经走到崩溃的边缘奄奄一息了。
以上仅为个人观点,若有谬误欢迎指正。