JAVA应用生产问题排查步骤( 二 )


JAVA应用生产问题排查步骤

文章插图
 
按键b打开或关闭 运行中进程的高亮效果
按键x打开或关闭 排序列的高亮效果
按数字 1 键 , 可以显示多个CPU的使用情况
JAVA应用生产问题排查步骤

文章插图
 
top显示的是服务器上面所有的进程概况,top类似于windows电脑上面的的任务管理器 。
JAVA应用生产问题排查步骤

文章插图
 
但是,如果我只关心我自己的JVM进程呢?可以使用这个命令
top -p jvm进程ID , 这个命令可以指定进程 , 只显示指定进程的概况 , 按空格键可以立即刷新 。
JAVA应用生产问题排查步骤

文章插图
 
top -d 2 -p jvm进程ID , 这个命令可以指定进程 , 只显示指定进程的概况 , -d 2的意思是俩秒钟刷新一次 。
JAVA应用生产问题排查步骤

文章插图
 
top -Hp 进程ID , 这个命令可以显示指定进程下面的线程信息 ,  这个超级有用 , 必须要会 。 而且这个命令搭配JAVA的自带命令jstack可以非常快速并且有效的定位代码问题 。
JAVA应用生产问题排查步骤

文章插图
 
然后使用linux的自带命令,printf将线程ID转换成16进制,printf “0x%xn” 19235
JAVA应用生产问题排查步骤

文章插图
 
然后使用JAVA的自带命令jstack去找到这个线程ID都在干什么就行了 。这几个命令非常非常重要 。
使用top命令 , 其实主要关注top命令里面的RES列的值,%CPU列的值,%MEM列的值,这三列的值就行了 。然后
拿RES列的值跟后面jmap命令显示的jvm堆的值做比较 。如果RES的值 , 比你的Xmx的值还大 ,  注意是比你设置的Xmx的值还大 ,说明你的java程序引用的有非堆(堆外地址)内存 , 比如NIO,DirectByteBuffer这些类会使用堆外的内存 。所以要注意堆外内存泄露情况(就是你代码里面虽然已经不用这块堆外地址了 , 但是你的引用没释放 , 导致你的程序浪费了很多用不到的堆外地址) 。堆外内存泄漏可以使用google出品的perf工具来排查 。perf工具使用参见,大神的文章 feininan 的文章《 使用google perf工具来排查堆外内存占用 》 。
这块知识点摘自网络上面 MartinDai 大神的文章 记一次堆外内存泄漏排查过程。执行top命令 , 再按c , 看到对应的进程所占用的RES有8个多G(这里当时忘记截图了) , 但是实际上我们配置的Xmx只有3G , 而且程序还是正常运行的 , 所以不会是堆占用了这么多 , 于是就把问题方向指向了非堆的内存 。
RES列和%MEM列的关系为:RES/总内存=%MEM,我们来算一下:
JAVA应用生产问题排查步骤

文章插图
 
从上图可以看到,这台服务器的物理内存(运存)为:132024628k = 126G.
32924这个进程的RES列的值为:5.3G
32924这个进程的%MEM列的值为:4.2%
我们来算一下:RES:5.3G / total Mem:126G = 0.042 = 4.2%
这下你明白了吧RES列和%MEM列,表达的其实是一个意思 。
RES的意思是:Resident Memory Size 常驻内存大小 。使用man top命令看下top命令的官方帮助文档怎么说:
JAVA应用生产问题排查步骤

文章插图
 

JAVA应用生产问题排查步骤

文章插图
 

JAVA应用生产问题排查步骤

文章插图
 
TIPS:按小写字母q可以退出top命令
JVM进程的RES列的值和JVM的heap(堆)的关系也很有意思,RES列的值代表JVM进程在运行过程中曾经使用过的最大内存, 注意是曾经使用过的最大内存 ,并不代表此时此刻JVM堆使用的内存大小 。举个例子,假如JVM在业务高峰期有大量请求进来,此时堆内存使用量肯定会上升,假如此时堆内存的使用量为5G,然后触发了JVM的垃圾回收,垃圾回收之后JVM堆内存使用量下降到了1G,此时你用top命令去看这个JVM进程的RES列的值有很大可能还是5G,原因就是这5G内存目前还归属JVM进程管理并使用,JVM 可能不会立即 把回收掉的堆空间还给操作系统 。


推荐阅读