深入理解Java虚拟机-监控与故障处理工具

 本章将讲述系统的性能监控命令及虚拟机性能监控与故障处理工具

  Linux系统性能分析及监控命令; 

      uptime、top、vmstat、pidstat、

  Windows常用监控工具

     Perfmon 、pslist

  Jvm常用的性能监控及故障处理分析工具;

     jps、jstack、jmap、jhat、jstat、hprof

系统性能监控- linux

 1.load average 定义

  linux系统中的Load对当前CPU工作量的度量。简单的说是进程队列的长度。

   Load Average 就是一段时间 (1 分钟、5分钟、15分钟) 内平均 Load 。

  通过系统命令"w"查看当前load average情况

 blob.png

  上边0.31,0.30,0.31表示

  第一位0.31:表示最近1分钟平均负载
  第二位0.30:表示最近5分钟平均负载
  第三位0.31:表示最近15分钟平均负载

  注:linux系统是5秒钟进行一次Load采样

 2. load average值的含义

   1) 单核处理器

     假设我们的系统是单CPU单内核的,把它比喻成是一条单向马路,把CPU任务比作汽车。当车不多的时候,load <1;当车占满整个马路的时候 load=1;当马路都站满了,而且马路外还堆满了汽车的时候,load>1

   2) 多核处理器

    我们经常会发现服务器Load > 1但是运行仍然不错,那是因为服务器是多核处理器(Multi-core)。
    假设我们服务器CPU是2核,那么将意味我们拥有2条马路,我们的Load = 2时,所有马路都跑满车辆。

    

   注:查看cpu 核数命令: 

    grep 'model name' /proc/cpuinfo | wc -l

   

    什么样的Load average值要提高警惕

    0.7 < load < 1: 此时是不错的状态,如果进来更多的汽车,你的马路仍然可以应付。load = 1: 你的马路即将拥堵,而且没有更多的资源额外的任务,赶紧看看发生了什么吧。load > 5: 非常严重拥堵,我们的马路非常繁忙,每辆车都无法很快的运行

3、uptime

 另外还有一个参数 -V(大写),是用来查询版本的

  uptime -V

  blob.png

  procps是一个实用程序包,主要包括ps top kill等程序主要用来显示与控制一些系统信息,进程状态之类的内容。

  以下显示输入uptime的信息:

    11:00:48 up 241 days, 15:44,  1 user,  load average: 0.79, 0.91, 0.80

 参数解析:

  当前时间 04:03:58

  系统已运行的时间  241 days, 15:44

  当前在线用户 1 user

  平均负载:0.79, 0.91, 0.80,最近1分钟、5分钟、15分钟系统的负载

  cat /proc/loadavg

  最直接查看系统平均负载命令

     [tomcatuser1@iZ946i6y47hZ ~]$ cat /proc/loadavg

      0.52 0.71 0.74 1/1704 12967

  除了前3个数字表示平均进程数量外,后面的1个分数,分母表示系统进程总数,分子表示正在运行的进程数;最后一个数字表示最近运行的进程ID

top命令监控:

blob.png

结果参数解析:

一.TOP前五行统计信息

统计信息区前五行是系统整体的统计信息。

1. 第一行是任务队列信息

同 uptime  命令的执行结果:

[root@localhost ~]# uptime

 13:22:30 up 8 min,  4 users,  load average: 0.14, 0.38, 0.25

其内容如下:

12:38:33

当前时间

up   50days

系统运行时间,格式为时:分

1   user

当前登录用户数

load   average: 0.06, 0.60, 0.48

系统负载,即任务队列的平均长度。 三个数值分别为  1分钟、5分钟、15分钟前到现在的平均值。

2. 第二、三行为进程和CPU的信息

当有多个CPU时,这些内容可能会超过两行。内容如下:

Tasks:   29 total

进程总数

1   running

正在运行的进程数

28   sleeping

睡眠的进程数

0   stopped

停止的进程数

0   zombie

僵尸进程数

Cpu(s):   0.3% us

用户空间占用CPU百分比

1.0%   sy

内核空间占用CPU百分比

0.0%   ni

用户进程空间内改变过优先级的进程占用CPU百分比

98.7%   id

空闲CPU百分比

0.0%   wa

等待输入输出的CPU时间百分比

0.0%   hi

0.0%   si

3. 第四五行为内存信息。

内容如下:

Mem: 191272k total

物理内存总量

173656k   used

使用的物理内存总量

17616k   free

空闲内存总量

22052k   buffers

用作内核缓存的内存量

Swap: 192772k total

交换区总量

0k   used

使用的交换区总量

192772k   free

空闲交换区总量

123988k   cached

缓冲的交换区总量。 内存中的内容被换出到交换区,而后又被换入到内存,但使用过的交换区尚未被覆盖, 该数值即为这些内容已存在于内存中的交换区的大小。相应的内存再次被换出时可不必再对交换区写入。

二.  进程信息

列名

含义

PID

进程id

PPID

父进程id

RUSER

Real   user name

UID

进程所有者的用户id

USER

进程所有者的用户名

GROUP

进程所有者的组名

TTY

启动进程的终端名。不是从终端启动的进程则显示为 ?

PR

优先级

NI

nice值。负值表示高优先级,正值表示低优先级

P

最后使用的CPU,仅在多CPU环境下有意义

%CPU

上次更新到现在的CPU时间占用百分比

TIME

进程使用的CPU时间总计,单位秒

TIME+

进程使用的CPU时间总计,单位1/100秒

%MEM

进程使用的物理内存百分比

VIRT

进程使用的虚拟内存总量,单位kb。VIRT=SWAP+RES

SWAP

进程使用的虚拟内存中,被换出的大小,单位kb。

RES

进程使用的、未被换出的物理内存大小,单位kb。RES=CODE+DATA

CODE

可执行代码占用的物理内存大小,单位kb

DATA

可执行代码以外的部分(数据段+栈)占用的物理内存大小,单位kb

SHR

共享内存大小,单位kb

nFLT

页面错误次数

nDRT

最后一次写入到现在,被修改过的页面数。

S

进程状态。
              D=不可中断的睡眠状态
              R=运行
              S=睡眠
              T=跟踪/停止
              Z=僵尸进程

COMMAND

命令名/命令行

WCHAN

若该进程在睡眠,则显示睡眠中的系统函数名

Flags

任务标志,参考 sched.h

vmstat命令:

vmstat命令是最常见的Linux/Unix监控工具,可以展现给定时间间隔的服务器的状态值,包括服务器的CPU使用率,内存使用,虚拟内存交换情况,IO读写情况。

 一般vmstat工具的使用是通过两个数字参数来完成的,第一个参数是采样的时间间隔数,单位是秒,第二个参数是采样的次数,如: 

 root@ubuntu:~# vmstat 2 1

 2表示每个两秒采集一次服务器状态,1表示只采集一次。

 实际上,在应用过程中,我们会在一段时间内一直监控,不想监控直接结束vmstat就行了,例如:

 blob.png

  这表示vmstat每2秒采集数据,一直采集,直到我结束程序,直到自己手动结束程序。

结果参数分析:

   r 表示运行队列(就是说多少个进程真的分配到CPU),我测试的服务器目前CPU比较空闲,没什么程序在跑,当这个值超过了CPU数目,就会出现CPU瓶颈了。这个也和top的负载有关系,一般负载超过了3就比较高,超过了5就高,超过了10就不正常了,服务器的状态很危险。top的负载类似每秒的运行队列。如果运行队列过大,表示你的CPU很繁忙,一般会造成CPU使用率很高。

   b 表示阻塞的进程,这个不多说,进程阻塞,大家懂的。

   swpd 虚拟内存已使用的大小,如果大于0,表示你的机器物理内存不足了,如果不是程序内存泄露的原因,那么你该升级内存了或者把耗内存的任务迁移到其他机器。

   free   空闲的物理内存的大小,剩余约180M。

   buff   Linux/Unix系统是用来存储,目录里面有什么内容,权限等的缓存,我本机大概占用18多M

   cache cache直接用来记忆我们打开的文件,给文件做缓冲,我本机大概占用130多M(这里是Linux/Unix的聪明之处,把空闲的物理内存的一部分拿来做文件和目录的缓存,是为了提高 程序执行的性能,当程序使用内存时,buffer/cached会很快地被使用。)

   si  每秒从磁盘读入虚拟内存的大小,如果这个值大于0,表示物理内存不够用或者内存泄露了,要查找耗内存进程解决掉。我的机器内存充裕,一切正常。

    so  每秒虚拟内存写入磁盘的大小,如果这个值大于0,同上。

    bi  块设备每秒接收的块数量,这里的块设备是指系统上所有的磁盘和其他块设备,默认块大小是1024byte,我本机上没什么IO操作,所以一直是0,但是我曾在处理拷贝大量数据(2-3T)的机器上看过可以达到140000/s,磁盘写入速度差不多140M每秒

    bo 块设备每秒发送的块数量,例如我们读取文件,bo就要大于0。bi和bo一般都要接近0,不然就是IO过于频繁,需要调整。

    in 每秒CPU的中断次数,包括时间中断

    cs 每秒上下文切换次数,例如我们调用系统函数,就要进行上下文切换,线程的切换,也要进程上下文切换,这个值要越小越好,太大了,要考虑调低线程或者进程的数目,例如在apache和nginx这种web服务器中,我们一般做性能测试时会进行几千并发甚至几万并发的测试,选择web服务器的进程可以由进程或者线程的峰值一直下调,压测,直到cs到一个比较小的值,这个进程和线程数就是比较合适的值了。系统调用也是,每次调用系统函数,我们的代码就会进入内核空间,导致上下文切换,这个是很耗资源,也要尽量避免频繁调用系统函数。上下文切换次数过多表示你的CPU大部分浪费在上下文切换,导致CPU干正经事的时间少了,CPU没有充分利用,是不可取的。

    us 用户CPU时间,我曾经在一个做加密解密很频繁的服务器上,可以看到us接近100,r运行队列达到80(机器在做压力测试,性能表现不佳)。

    sy 系统CPU时间,如果太高,表示系统调用时间长,例如是IO操作频繁。

    id  空闲 CPU时间,一般来说,id + us + sy = 100,一般我认为id是空闲CPU使用率,us是用户CPU使用率,sy是系统CPU使用率。

    wt 等待IO CPU时间。

pidstat命令:

 pidstat主要用于监控全部或指定进程占用系统资源的情况,如CPU,内存、设备IO、任务切换、线程等。pidstat首次运行时显示自系统启动开始的各项统计信息,之后运行pidstat将显示自上次运行该命令以后的统计信息。用户可以通过指定统计的次数和时间来获得所需的统计信息。

  执行pidstat,将输出系统启动后所有活动进程的cpu统计信息:

  blob.png

  

 指定采样周期和采样次数

   pidstat命令指定采样周期和采样次数,命令形式为”pidstat [option] interval [count]”,以下pidstat输出以2秒为采样周期,输出10次cpu使用统计信息:

   pidstat 2 10

   cpu使用情况统计(-u)

   使用-u选项,pidstat将显示各活动进程的cpu使用统计,执行”pidstat -u”与单独执行”pidstat”的效果一样。

   内存使用情况统计(-r)

   使用-r选项,pidstat将显示各活动进程的内存使用统计:

  blob.png

  以上各列输出的含义如下:

    minflt/s: 每秒次缺页错误次数(minor page faults),次缺页错误次数意即虚拟内存地址映射成物理内存地址产生的page fault次数

    majflt/s: 每秒主缺页错误次数(major page faults),当虚拟内存地址映射成物理内存地址时,相应的page在swap中,这样的page fault为major page        fault,一般在内存使用紧张时产生

    VSZ:      该进程使用的虚拟内存(以kB为单位)

    RSS:      该进程使用的物理内存(以kB为单位)

    %MEM:     该进程使用内存的百分比

    Command:  拉起进程对应的命令

 

    其他选项命令:

     使用-d选项,我们可以查看进程IO的统计信息:

   使用-p选项,我们可以查看特定进程的系统资源使用情况:

系统性能监控 – windows

  Windows的性能分析我就不详细的分析,主要是通过查看Window自带的性能监控工具,如:性能监视器/Perfmon 、pslist

   blob.png

  

JVM 常用的性能监控与故障处理工具:

  JDK本身提供了很多方便的JVM性能调优监控工具,除了集成式的VisualVM和jConsole外,还有jps、jstack、jmap、jhat、jstat、hprof等小巧的工具,详细的可以查查阅深入理解Java虚拟机第4章节:

 Java自带的工具

  blob.png

JPS :虚拟机进程状况工具

  jps主要用来输出JVM中运行的进程状态信息。语法格式如下:

     jps [options] [hostid]

  如果不指定hostid就默认为当前主机或服务器。     

 命令行参数选项说明如下: 

  1 -q 不输出类名、Jar名和传入main方法的参数 

  2 -m 输出传入main方法的参数 

  3 -l 输出main类或Jar的全限名 

  4 -v 输出传入JVM的参数 

 比如下面:

 blob.png

jstack :Java堆栈跟踪工具。

 jstack主要用来查看某个Java进程内的线程堆栈信息。语法格式如下:

    1 jstack [option] pid 

    2 jstack [option] executable core 

    3 jstack [option] [server-id@]remote-hostname-or-ip

 命令行参数选项说明如下:

   -l long listings,会打印出额外的锁信息,在发生死锁时可以用jstack -l pid来观察锁持有情况

   -m mixed mode,不仅会输出Java堆栈信息,还会输出C/C++堆栈信息(比如Native方法)

  jstack可以定位到线程堆栈,根据堆栈信息我们可以定位到具体代码,所以它在JVM性能调优中使用得非常多。下面我们来一个实例找出某个Java进程中最耗费CPU的Java线程并定位堆栈信息,用到的命令有ps、top、printf、jstack、grep。

   第一步先找出Java进程ID,我部署在服务器上的Java应用:

  [tomcatuser1@iZ946i6y47hZ ~]$ ps -ef|grep java |grep -v grep

  blob.png

  得到进程ID为20556,第二步找出该进程内最耗费CPU的线程,可以使用ps -Lfp pid或者ps -mp pid -o THREAD, tid, time或者top -Hp pid,我这里用第三个,输出如下:

  blob.png

  TIME列就是各个Java线程耗费的CPU时间,CPU时间最长的是线程ID为20562的线程,用

    printf "%x\n" 20562

  得到20562的十六进制值为54ee,下面会用到。

  blob.png

  2052;

  O K,下一步终于轮到jstack上场了,它用来输出进程20562的堆栈信息,然后根据线程ID的十六进制值grep,如下:

   blob.png

   可以看到CPU消耗在C3P0PooledConnectionPoolManager这个类的Object.wait();

jmap:Java内存映像工具

   jmap用来查看堆内存使用状况,一般结合jhat使用。

   jmap语法格式如下:

     jmap [option] pid

     如果运行在64位JVM上,由于linux操作系统的不同,可能需要指定-J-d64命令选项参数。

   基本参数:

    -dump:[live,]format=b,file=<filename> 使用hprof二进制形式,输出jvm的heap内容到文件=. live子选项是可选的,假如指定live选项,那么只输出活的对象到文件. 

   -finalizerinfo 打印正等候回收的对象的信息.

   -heap 打印heap的概要信息,GC使用的算法,heap的配置及wise heap的使用情况.

    -histo[:live] 打印每个class的实例数目,内存占用,类全名信息. VM的内部类名字开头会加上前缀”*”. 如果live子参数加上后,只统计活的对象数量. 

    -permstat 打印classload和jvm heap长久层的信息. 包含每个classloader的名字,活泼性,地址,父classloader和加载的class数量. 另外,内部String的数量和占用内存数也会打印出来. 

     -F 强迫.在pid没有相应的时候使用-dump或者-histo参数. 在这个模式下,live子参数无效. 

     -h | -help 打印辅助信息 

     -J 传递参数给jmap启动的jvm.

使用示例

  使用jmap -histo[:live] pid查看堆内存中的对象数目、大小统计直方图,如果带上live则只统计活对象,如下:

  1)、[fenglb@ccbu-156-5 ~]$ jmap -histo 4939 > a.log

 使用jmap -heap pid查看进程堆内存使用情况,包括使用的GC算法、堆配置参数和各代中堆内存使用情况。比如下面的例子:

 blob.png

  还有一个很常用的情况是:用jmap把进程内存使用情况dump到文件中,再用jhat分析查看。jmap进行dump命令格式如下:

   jmap -dump:format=b,file=dumpFileName pid

   我一样地对上面进程ID为21711进行Dump:

   root@ubuntu:/# jmap -dump:format=b,file=/tmp/dump.dat 21711   

   

  dump出来的文件可以用MAT、VisualVM等工具查看,这里用jhat查看:

  dump出来的文件可以用MAT、VisualVM等工具查看,这里用jhat查看:

jstat(JVM统计监测工具)

  语法格式如下:

  jstat [ generalOption | outputOptions vmid [interval[s|ms] [count]] ]

  vmid是Java虚拟机ID,在Linux/Unix系统上一般就是进程ID。interval是采样时间间隔。count是采样数目。比如下面输出的是GC信息,采样时间间隔为250ms,采样数为4:

 blob.png

 要明白上面各列的意义,先看JVM堆内存布局:

 blob.png

  

  可以看出:

  堆内存 = 年轻代 + 年老代 + 永久代

  年轻代 = Eden区 + 两个Survivor区(From和To)

    现在来解释各列含义:

    S0C、S1C、S0U、S1U:Survivor 0/1区容量(Capacity)和使用量(Used)

    EC、EU:Eden区容量和使用量

    OC、OU:年老代容量和使用量

    PC、PU:永久代容量和使用量

    YGC、YGT:年轻代GC次数和GC耗时

    FGC、FGCT:Full GC次数和Full GC耗时

    GCT:GC总耗时

JVM性能调优参考资料:

 《深入理解Java虚拟机》

 http://www.cnitblog.com/tjitty/archive/2010/07/12/67429.html

 http://www.open-open.com/lib/view/open1390916852007.html

 http://blog.csdn.net/fenglibing/article/details/6411924

 linux中uptime命令查看linux系统负载

 Linux vmstat命令实战详解

 Linux 运行进程实时监控pidstat命令详解

     

发表评论