【JVM】线上应用故障排查

 

 

高CPU占用

一个应用占用CPU很高,除了确实是计算密集型应用以外,一般缘由都是出现了死循环。html

 

根据top命令,发现PID为28555的Java进程占用CPU高达200%,出现故障。java

经过ps aux | grep PID命令,能够进一步肯定是tomcat进程出现了问题。可是,怎么定位到具体线程或者代码呢?数组

首先显示线程列表:tomcat

ps -mp pid -o THREAD,tid,time工具

找到了耗时最高的线程28802,占用CPU时间快两个小时了!post

 

其次将须要的线程ID转换为16进制格式:spa

printf "%x\n" tid.net

 

 

最后打印线程的堆栈信息:线程

jstack pid |grep tid -A 303d

 

 找到出现问题的代码了!

 

最后,总结下排查CPU故障的方法和技巧有哪些:

一、top命令:Linux命令。能够查看实时的CPU使用状况。也能够查看最近一段时间的CPU使用状况。

二、PS命令:Linux命令。强大的进程状态监控命令。能够查看进程以及进程中线程的当前CPU使用状况。属于当前状态的采样数据。

三、jstack:Java提供的命令。能够查看某个进程的当前线程栈运行状况。根据这个命令的输出能够定位某个进程的全部线程的当前运行状态、运行代码,以及是否死锁等等。

四、pstack:Linux命令。能够查看某个进程的当前线程栈运行状况。

 

 

高内存占用

搞Java开发的,常常会碰到下面两种异常:

一、java.lang.OutOfMemoryError: PermGen space

二、java.lang.OutOfMemoryError: Java heap space

要详细解释这两种异常,须要简单重提下Java内存模型。

 

Java内存模型是描述Java程序中各变量(实例域、静态域和数组元素)之间的关系,以及在实际计算机系统中将变量存储到内存和从内存取出变量这样的低层细节。

在Java虚拟机中,内存分为三个代:新生代(New)、老生代(Old)、永久代(Perm)。

(1)新生代New:新建的对象都存放这里

(2)老生代Old:存放重新生代New中迁移过来的生命周期较久的对象。新生代New和老生代Old共同组成了堆内存。

(3)永久代Perm:是非堆内存的组成部分。主要存放加载的Class类级对象如class自己,method,field等等。

若是出现java.lang.OutOfMemoryError: Java heap space异常,说明Java虚拟机的堆内存不够。缘由有二:

(1)Java虚拟机的堆内存设置不够,能够经过参数-Xms、-Xmx来调整。

(2)代码中建立了大量大对象,而且长时间不能被垃圾收集器收集(存在被引用)。

若是出现java.lang.OutOfMemoryError: PermGen space,说明是Java虚拟机对永久代Perm内存设置不够。

通常出现这种状况,都是程序启动须要加载大量的第三方jar包。例如:在一个Tomcat下部署了太多的应用。

 

从代码的角度,软件开发人员主要关注java.lang.OutOfMemoryError: Java heap space异常,减小没必要要的对象建立,同时避免内存泄漏。

如今以一个实际的例子分析内存占用的故障排查。

2G19({7(0}N(FIL09LH175N

经过top命令,发现PID为9004的Java进程一直占用比较高的内存不释放(24.7%),出现高内存占用的故障。

想起上一篇线上应用故障排查之一:高CPU占用介绍的PS命令,可否找到具体是哪一个的线程呢?

ps -mp 9004 -o THREAD,tid,time,rss,size,%mem

1

遗憾的是,发现PS命令能够查到具体进程的CPU占用状况,可是不能查到一个进程下具体线程的内存占用状况。

 

只好寻求其余方法了,幸亏Java提供了一个很好的内存监控工具:jmap命令

jmap命令有下面几种经常使用的用法:

•jmap [pid]

•jmap -histo:live [pid] >a.log

•jmap -dump:live,format=b,file=xxx.xxx [pid]

用得最可能是后面两个。其中,jmap -histo:live [pid] 能够查看当前Java进程建立的活跃对象数目和占用内存大小。

jmap -dump:live,format=b,file=xxx.xxx [pid] 则能够将当前Java进程的内存占用状况导出来,方便用专门的内存分析工具(例如:MAT)来分析。

这个命令对于分析是否有内存泄漏颇有帮助。具体怎么使用能够查看本博的另外一篇文章:利用Eclipse Memory Analyzer Tool(MAT)分析内存泄漏

 

这里详细介绍下jmap -histo:live [pid] 命令:

1

从上图能够看出,int数组、constMethodKlass、methodKlass、constantPoolKlass都占用了大量的内存。

特别是占用了大量内存的int数组,须要仔细检查相关代码。

 

最后,总结下排查内存故障的方法和技巧有哪些:

一、top命令:Linux命令。能够查看实时的内存使用状况。  

二、jmap -histo:live [pid],而后分析具体的对象数目和占用内存大小,从而定位代码。

三、jmap -dump:live,format=b,file=xxx.xxx [pid],而后利用MAT工具分析是否存在内存泄漏等等。

相关文章
相关标签/搜索