背景
身为运维人员,总是会遇到一个情况,跑在自己服务器上的一个java程序,占用的cpu突然飙升,导致服务器宕机。
大概率是java程序内存溢出,服务疯狂FullGC,导致的cpu飙升。
那如何分析cpu飙升的原因,以及如果是内存泄露,运维人员如何定位到具体代码反馈给开发人员,下面我介绍一些方法
步骤
一、定位占用CPU最高的服务
1、先找到cpu占用比较高的进程:top -c 进去后按Shift+P键
一般异常的进程cpu的占用会很高,记录下这进程的PID
2、查看指定进程cpu情况:top -cp <PID>
查看此进程占用cpu最高的线程,记录下线程的ppid
也可以将相关信息保存下来:top -Hp <PID> -o %CPU -n 1 >cpu.txt
到此,我们就找到的最占用cpu的进程以及相关线程
二、打印进程堆栈,定位到问题代码
1、将进程的堆栈打印出来,jstack <PID> > jstack.txt
2、将线程id(ppid)转换成16进制后在jstack.txt搜索:printf ‘0x%x’ <ppid>
3、将cpu.txt和jstack.txt给开发定位,我们重启java服务
三、还可以通过show-busy-java-thread脚本快速定位(代替 标题一 + 标题二 )
1、wget --no-check-certificate https://github.com/oldratlee/useful-scripts/archive/release.zip下载
2、unzip release.zip
3、sh show-busy-java-threads.sh 从所有运行的Java进程中找出最消耗CPU的线程(缺省5个),打印出其线程栈(同排除思路)
4、也可以指定进程:show-busy-java-threads -p <指定的Java进程Id>
四、内存溢出定位
1、如果(标题一 + 标题二)或者标题三定位出来的问题是GC线程占用了大量cpu
那就是典型的内存溢出现象
java服务内存溢出,导致一直调用GC线程,导致cpu上升
那我们还需要继续定位是哪一行代码导致的内存溢出
2、打印java进程堆栈
jmap -dump:format=b,file=xxx.hprof <pid>
3、将打印下来的堆栈放到JProfiler分析,打开hprof快照
4、点击最大对象,对占用内存最大的对象,右键点击使用选定对象-引用-传入引用
5、点击显示到GC根路径
显示更多中的信息就是整一个代码调用链
将显示更多中的信息给到开发,开发就可以定位到是哪一条代码存在内存泄露风险
建议
1、开发人员在开发大量数据导入的场景,一定要注意内存溢出的问题
2、测试阶段需要做内存溢出方面的性能测试