有时候好好的程序放到生产服务器上一段时间后,就会发现服务器响应缓慢,进而进一步发现是cpu太高,因而就慌了,形成cpu太高的缘由不少,不过大可能是因为资源吃紧形成,例如:sql执行过慢,程序里存在死循环,数据库链接未释放,网络阻塞致使的第三方框架代码出现死循环,大量的操做致使死锁等html
public class CpuTest { public static void main(String[] args) throws InterruptedException { loop(); endlessLoop(); } public static void endlessLoop() throws InterruptedException { while (true) { System.out.println("hello world! loop!"); } } public static void loop(){ for (int i = 0; i < 10000; i++) { System.out.println("hello world! endless loop!"); } } }
分析点击抽样器->CPU->查看CPU样例,发现endlessLoop()方法最耗CPU(这里有2个方法 loop和endlessLoop)java
查看线程cpu耗时,发现main线程最耗时,点击增量,能够今后刻观察,cpu耗时的增加速率node
查看线程dump,主要观察main线程,发现main线程当前状态下一直在执行CpuTest.endlessLoop(CpuTest.java:14)
,这里能够定位问题位置,同时细心的童鞋能够观察看后面执行System.out.println("");方法是要先加锁的。linux
截图一段,我生产服务器(tomcat+springmvc)main线程的状况,其实只想说明web项目启动的main方法在中间件里。web
VisualVm只能定位JVM的cpu状况,可是生产主机上不光是Java程序,这时咱们要采起另外的方案。算法
1.看监控数据是否正常,cpu,mem。spring
CPU占用1.5左右(100-98.0id) 内存占用50%(435/100*100%=43.5%) 阿里云监控内存大小转成实际占用内存大小,相似windows ,平均负载 0.1 差很少,其余几个参数,这里暂不介绍。sql
2.假设异常,找到异常的PID。数据库
这里推荐htop
(清晰进程,线程,命令行,排序支持鼠标双击,过滤,kill程序,标记某个线程或者进程,安装apt-get install htop
)windows
若是你没有服务器上安装软件的权限的话,就老老实实用top
。经过top
命令(默认3秒刷新,回车空格手动刷新,top -d 5
5秒刷新,也能够进入top后输入d
设置刷新时间,top -p 4360
监控指定进程),而后按X ,默认按照CPU%排序,查看系统运行状况,若是想强制按CPU 降序,则输入大写P,若是强制按内存降序,则输入大写M(top命令是交互式的)。
解读:
1).如今系统时间 10:18.44 ,系统一直运行了 131天16小时51分,当前有1个用户登陆系统(相同帐号也算不一样用户),平均负载分别为0.00,0.01,0.05(分别为1分钟,5分钟,15分钟的负载状况,load average是每隔5秒钟检查一次活跃的进程数,用特定的算法获得的数值,而后除以逻辑CPU数量,若是负载持续大于cpu个数,则代表负载太高) 。大概能够看出系统负载很低,运行状态健康。
2).当前一共有103个进程,处于运行的有2个,处于休眠状态的有101个,处于中止状态的有0个,处于僵尸状态的有0个。大概能够看出系统进程总数较少,环境比较单纯,运行中的进程很少。
3).0.3 us
用户空间占用CPU 0.3%,0.7 sy
内核占用CPU 0.7%,0.0 ni
改变过优先级的进程占用CPU的百分比,98.0 id
空闲CPU的百分比为98.0,0.3 wa
IO等待所占用CPU的百分比为0.3,0.3 hi
硬中断(Hardware IRQ)占用CPU的百分比为0.3(外设给CPU的异步信号(中断),例如:网卡收到数据包),0.0 si
软中断占用cpu的百分比为0(软件自己给操做系统内核的中断信号,一般由硬中断处理程序对操做系统内核的中断),0.3 st
虚拟机被hypervisor偷去CPU的时间。
4).KiB Mem
表明内存占用,1016272 total
内存总的大小1g(以kb为单位),941492 used
使用中的内存总量为0.9g,74780 free
空闲内存总量为74m(吓一跳吧,才74M,这个不是实际剩余的内内存大小),115900 buffers
缓存的内存量为115m,389836 cached
cached大小380M。空闲内存总量只有74m,若是是windows去理解的话,此台服务器已经快挂了,实际内存大小等于74M+ buffers+cached = 580m(哈哈,够用,才占用一半呢), linux的内存管理和windows是不同的,Linux会借用空闲的内存看成磁盘缓存, 磁盘数据缓存会让linux运行的更快,它永远不会从程序中拿出内存,它没有任何缺点,只是会混淆新手,若是你的应用程序须要更多的内存,他们会回收一部分用做磁盘数据缓存的物理内存,返回给应用程序,这个过程不须要启动交换,磁盘缓存(Disk caching)是不能禁用的, 可是能够释放磁盘缓存 1).只释放pagecache(文件缓存) echo 1 > /proc/sys/vm/drop_caches
2).释放dentries和inodes echo 2 > /proc/sys/vm/drop_caches
3).释放pagecache,dentries和inodes echo 3 > /proc/sys/vm/drop_caches
具体原理能够查看linuxatemyram
咱们利用free
进一步证明上面的内容
1).shared表明被线程共享的内存大小(大多数已经舍弃掉),buffer用来给块设备作缓存(记录文件系统的metadata和tracking in flight pages),cache缓存文件(第二次打开就很快),linux系统cached比较大,cached大小390m,buffers为110m。
2).435288表明 -buffers/cache (应用程序实际使用330m内存) 580984 表明 +buffers/cache(实际剩余内存大小580m)。
3).重要等式 total = used + free
used(-buffers/cache) = used(Mem)-buffers(Mem)-cached(Mem)
free(+buffers/cache) = free(Mem) + buffers(Mem) +cached(Mem)
。
4).free
命令的值是从 /proc/meminfo 文件里读到的。
5).Swap 交换区 总共大小 0 kb,已经使用0kb,释放了0Kb,若是swap used > 0,则能够说明系统内存瓶颈了。
6).内存总和 free -t
总和等于total(Mem) + total(Swap)。
7).通常经常使用命令 free -s 3
每3秒观察一次内存使用状况。
占用cpu最高的进程是java,PID为28628,USER进程全部者root,PR优先级20,NI为0(负值优先级高,正值优先级低,PR=NI+20) ,VIRT进程使用虚拟内存1G(java进程最高只能占用到1G),RES进程实际使用的物理内存270M(不包含swap和shared),SHR共享内存大小5M,S进程状态随眠状态(S睡眠,R运行,T中止或被跟踪,Z僵尸,D不可中断睡眠态),%CPU占用CPU 0.7%,%MEM占用内存27%,TIME+进程使用cpu的时间54分40.12秒。整体看java进程运行良好。
3.这里假设PID为16368的进程占用CPU比较高(由于作了屡次实验,因此PID没办法和上面的28628保持一致),
先用ps -ef | grep java
,也能够用htop
filter java,也能够jps -v
找到 java的进程ID 16368(只能查看当前用户的java pid,不太建议使用,-v显示详细信息,也能够不加)
?表明终端设备未知,Sl表明休眠状态多线程
Linux经过进程查看线程的方法 1).htop
按t(显示进程线程嵌套关系)和H(显示线程) ,而后F4过滤进程名。2).ps -eLf | grep java
(快照,带线程命令,e是显示所有进程,L是显示线程,f全格式输出) 3).pstree -p <pid>
(显示进程树,不加pid显示全部) 4).top -Hp <pid>
(实时) 5).ps -T -p <pid>
(快照) 推荐程度按数字从小到大。
4.利用jstack 16368 > 2016-1-21.tdump
(jstack是jdk自带的生成java stack和native stack的工具) 把threaddump输出到文件里,这里假设PID为16369(通常比进程号+1的是main线程,若是存在main线程貌似最早分配)的线程占用CPU最高,将其ID转成16进制0x3ff1(使用命令 printf "%x\n" 16369
输出3ff1)。
5.搜索threaddump文件,nid= 0x3ff1的线程堆栈,经过堆栈信息,就能够定位到占用CPU最高的代码地方(这里是正常的)。
好啦,CPU冲高问题排查完毕,有了这样的知识体系,之后彻底能够触类旁通,coder君同时附上其余经常使用配合命令。
jstat -gcutil 16368 1000ms
参考jstat -help
,也能够查看远程主机的GC状况,须要远程主机开启jstatd服务。
jmap -dump:format=b,file=2016-1-21.mdump 16368
生成堆dump,放到mat或者vvm进行分析,上篇分析OOM有讲到。
jinfo 16368
感谢您的耐心阅读,若是您发现文章中有一些没表述清楚的,或者是不对的地方,请给我留言,你的鼓励是做者写做最大的动力,
若是您认为本文质量不错,读后以为收获很大,不妨小额赞助我一下,让我更有动力继续写出高质量的文章。
做 者 : @mousycoder
原文出处 : http://mousycoder.com/2016/02...
创做时间:2016-2-14
更新时间:2016-2-14