java进程爆cpu的快速定位
1、背景
在程序开发的过程中,难免遇到进程占用cpu过高(现网居多、开发环境)的情况,现网出现这种情况就需要及时的能定位到问题,快速解决,否则就导致系统不可用,用户投诉等多种一系列的问题。
2、java进程占用CPU过高常见的两种情况:
- 代码中有死循环或者接近死循环的操作
- 快速创建大量临时变量,导致频繁触发gc回收
3、在windows中的定位方法
如图所示:
用jvisualvm 和 jconsole貌似都只能看到总共占用的cpu 看不到每个线程分别占用的cpu。
所以在windows平台上要找出到底是哪个线程占用的cpu还不那么容易,linux用top就行了。
3、定位步骤:
3.1、找到java进程对应的pid。
找pid的方法是:打开任务管理器,然后点击 “查看” 菜单,然后点击 “选择列”,把pid勾上,然后就可以在任务管理器里面看到所有进程的pid值了。
(也可以用第三步中提到的工具直接查看),在win10详细信息里面直接可以看到pid值。
3.2.然后把java进程导出快照。直接运行命令。
找到导出的文件打开d:/jstack182880.stack文件。
3.3、在windows下只能查看进程的cpu占用率,要查看线程的cpu占用率要借助其他的工具,这里用的是微软提供的 Process Explorer v15.3
下载地址:点击这里下载
下载完后解压运行
找到cpu占用高的线程,双击显示如图,或者右键点击需要查看的进程—properties
3.4.然后选择 Threads 选项卡,找到占用cpu的线程的tid,比如我这里是 224664 的线程
这里我们可以发现有多个线程占用7%左右,导致cpu占用较高
3.5.把pid转换成16进制,我这里直接用系统自带的计算器转换,置于为什么要转换,是因为先前用jstack导出的信息里面线程对应的tid是16进制的。
3.6.在 d:/jstack182880.stack文件中查找 36d98
找到相关代码,定位出问题所在。
4、在linux中的定位方法
4.1.找到CPU占用高的进程号 如:使用top命令查看(可以使用其它方法,只要找到对应的进程号即可)
注:图中第一列PID为进程号;
4.2、根据进程号找到CPU占用高的线程
如:使用命令top -H -p (其中要换成第一步找到的进程号)
注:图中第一列PID此时为线程号;
4.3.导出java进程执行堆栈,并找到对应的线程
使用jstack > jstack_xxx.txt (其中要换成第一步找到的进程号)
从第二步中的PID中找出一个CPU占用高的线程号,把它转成16进制,比如3261转成CBD
从导出的堆栈信息里找到nid为cbd的线程堆栈
4.4:从堆栈里找到对应的代码执行类和方法
若代码为业务代码,则需要具体分析代码,找出代码中死循环或接近死循环的地方,并修正;定位结束;
若堆栈信息为gc线程(类似下图),则需要进行下一步
4.5:dump出java进程的堆对象使用情况
使用jmap -histo > jmap_xxx.txt
找出量比较大的、且跟业务有关的对象,找到这些对象创建的地方进行分析;一般需要持续创建大量的对象,使得内存不够用时,才会频繁触发gc进行回收,gc回收时jvm有停顿,CPU也占用很高。
线程之间的切换,是很耗费性能的,所以带来CPU飙升.
新生代设置过小,也会频繁触发gc。有大对象始终根节点路径可达,无法释放,jvm在疯狂的Full GC。