原文地址:http://www.javatang.comhtml
前一段时间上线的系统升级以后,出现了严重的高CPU的问题,因而开始了一系列的优化处理之中,如今将这个过程作成一个系列的文章。java
基本概念shell
在对Java内存泄漏进行分析的时候,须要对jvm运行期间的内存占用、线程执行等状况进行记录的dump文件,经常使用的主要有thread dump和heap dump。bash
上面两种dump文件都具备实时性,所以须要在服务器出现问题的时候生成,而且多生成几个文件,方便进行对比分析。下面咱们先来讲一下如何生成 thread dump。服务器
当服务器出现高CPU的时候,首先执行 top -c
命令动态显示进程及占用资源的排行,以下图:
top后面的参数-c
能够显示进程详细的信息。top
命令执行的时候还能够执行一些快捷键:oracle
1
对于多核服务器,能够显示各个CPU占用资源的状况shift+h
显示全部的线程信息shift+w
将当前 top
命令的设置保存到 ~/.toprc
文件中,这样不用每次都执行快捷键了以上图为例,pid为1503的进程占用了大量的CPU资源,接下来须要将占用CPU最高进程中的线程打印出来,能够用 top -bn1 -H -p <pid>
命令,执行结果以下:
上面 -bn1
参数的含义是只输出一次结果,而不是显示一个动态的结果。框架
我我的请喜欢用 ps -mp <pid> -o THREAD,tid,time | sort -k2r
命令查看,后面的sort参数根据线程占用的cpu比例进行排序,结果以下:jvm
接下来咱们清楚今天的主角 jstack
,这是一个在JDK5开始提供的内置工具,能够打印指定进程中线程运行的状态,包括线程数量、是否存在死锁、资源竞争状况和线程的状态等等。有下面的几个经常使用的参数:工具
-l
长列表,打印关于锁的附加信息-m
打印java和jni框架的全部栈信息由于thread id在栈信息中是以十六进制的形式显示的,所以须要使用 printf "%x \n" <tid>
命令将现场id转成十六进制的值,而后执行 jstack -l <pid> | grep <thread-hex-id> -A 10
命令显示出错的堆栈信息,以下图:
上面命令中 -A 10
参数用来指定显示行数,不然只会显示一行信息。优化
这样经过上图,能够很快地定位到程序问题的代码,而后对代码进行分析和改进便可。注意:须要在多个时间段提出多个 Thread Dump信息,而后综合进行对比分析,单独分析一个文件是没有意义的。
上面讲述了整个的分析过程,不过全部的命令就是实时的,因此最好建立一个shell脚本瞬间执行完成,下面对 当CPU飙高时,它在作什么 这篇文章中所提供的shell进行了改进以下:
#!/bin/bash if [ $# -ne 1 ]; then echo "usage: $0 <pid> [line-number]" exit 1 fi # java home if test -z $JAVA_HOME then JAVA_HOME='/usr/local/jdk' fi #pid pid=$1 # checking pid if test -z "$($JAVA_HOME/bin/jps -l | cut -d '' -f 1 | grep $pid)" then echo "process of $pid is not exists" exit fi #line number if test -z $linenum then linenum=10 fi stackfile=stack$pid.dump threadsfile=threads$pid.dump # generate java stack $JAVA_HOME/bin/jstack -l $pid >> $stackfile ps -mp $pid -o THREAD,tid,time | sort -k2r | awk '{if ($1 !="USER" && $2 != "0.0" && $8 !="-") print $8;}' | xargs printf "%x\n" >> $threadsfile tids="$(cat $threadsfile)" for tid in $tids do echo "------------------------------ ThreadId ($tid) ------------------------------" cat $stackfile | grep 0x$tid -A $linenum done rm -f $stackfile $threadsfile
下一篇文章将要讲述如何对jstack生成的文件进行分析