jvm学习记录--07 性能监控操作系统篇

linux系统监控工具

top命令

top命令可以从宏观上观察操作系统的cpu,内存使用情况,以及每个进程的使用cpu情况,内存情况。

参数说明

-b         : 批处理
-c         : 显示完整的命令
-I         : 忽略失效过程
-s         : 保密模式
-S         : 累积模式
-i<时间>    : 设置间隔时间
-u<用户名>  : 指定用户名
-p<进程号>  : 指定进程
-n<次数>    : 循环显示的次数

jvm学习记录--07 性能监控操作系统篇_第1张图片

top命令的输出可以分为两个部分:前半部分是系统统计信息,后半部分是进程信息。

统计信息

1行是任务队列信息,它的结果等同于uptime命令。从左到右依次表示
系统当前时间、
系统运行时间、
当前登录用户数。
load average表示系统的平均负载,即任务队列的长度,这三个值分别表示1分钟、5分钟、15分钟到现在的平均值。
第2行表示
总进程数,
正在运行的进程数,
休眠的进程数,
停止的进程数,
僵尸进程数。
3行是cpu信息:
us 用户空间占用CPU百分比
sy 内核空间占用CPU百分比
ni 用户进程空间内改变过优先级的进程占用CPU百分比
id 空闲CPU百分比
wa 等待输入输出的CPU时间百分比
hi 硬件中断
si 软件中断 
st: 实时
第4行是内存信息:依次显示
物理内存总量,
空闲物理内存,
已经使用的内存,
内核缓冲使用量,
第5行显示的交换空间信息:依次表示
交换空间总量
空闲空间总量
已经使用空间总量
缓冲区使用总量

进程信息

PI     :进程ID
USE    :进程所有者
PR     :进程优先级
NI     :nice值.负值表示高优先级,正值表示低优先级
VIRT   :进程使用的虚拟内存总量,单位KB.VIRT=SWAP+RES
RES    :进程使用的,违背换出的物理内存大小,单位KB.RES=CODE+DATA
SHR    :共享内存大小,单位KB
S      :进程状态.D(不可中断的睡眠状态),R,S,T(跟踪/停止),Z
%CPU   :上次更新到现在的CPU时间占用百分比
%MEM   :进程使用的物理内存百分比
TIME+  :进程使用的CPU时间总计,单位1/100秒
COMMAND:进程名称(命令行/命令名)

vmstat命令

vmstat命令是最常见的Linux/Unix监控工具,可以展现给定时间间隔的服务器的状态值,包括服务器的CPU使用率,内存使用,虚拟内存交换情况,IO读写情况。这个命令是我查看Linux/Unix最喜爱的命令,一个是Linux/Unix都支持,二是相比top,我可以看到整个机器的CPU,内存,IO的使用情况,而不是单单看到各个进程的CPU使用率和内存使用率(使用场景不一样)。

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

root@ubuntu:~# vmstat 2 1
procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa
 1  0      0 3498472 315836 3819540    0    0     0     1    2    0  0  0 100  0

2表示每个两秒采集一次服务器状态,1表示只采集一次。
如果不输入第二个参数就表示一直采集。

参数说明

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

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

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

free 空闲的物理内存的大小,我的机器内存总共8G,剩余3415M。

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

cache cache直接用来记忆我们打开的文件,给文件做缓冲,我本机大概占用300多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时间

iostat命令

iostat 命令可以提供详细的io信息.

基本用法
-d表示输出磁盘使用情况
1 表示每秒钟采样一次
2 表示采集两次

iostat -d 1 2

输出结果:

Linux 3.10.0-514.el7.x86_64 (localhost.localdomain)     20171110日     _x86_64_    (2 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           0.05    0.00    0.11    0.02    0.00   99.82

Device:            tps    kB_read/s    kB_wrtn/s    kB_read    kB_wrtn
sda               0.48         3.49        14.65     295477    1240842
dm-0              0.54         3.12        14.61     264528    1237637
dm-1              0.01         0.02         0.01       1640       1084

说明:

tps:该设备每秒的传输次数
kB_read/s:每秒从设备(drive expressed)读取的数据量;
kB_wrtn/s:每秒向设备(drive expressed)写入的数据量;
kB_read:读取的总数据量;
kB_wrtn:写入的总数量数据量;这些单位都为Kilobytes。

如果要看更加相信的可以用-x

iostat -x 1 2

jvm学习记录--07 性能监控操作系统篇_第2张图片

pidstat

pidstat是sysstat的一个组件,不仅仅可以检测进程使用cpu,io,内存情况,甚至可以深入到进程中的线程使用情况。

需要安装sysstat

yum -y install sysstat

检查cpu性能

它不仅仅可以监测进程的性能,还可以监测线程的性能。

运行一个Java程序,这里打成了jar包运行(jar名字1.jar),源码如下(T1的线程不休眠消耗cpu,T2会休眠不怎么消耗cpu):

public class HoldCpuMain {
    static class T1 implements Runnable{
        @Override
        public void run() {
            while(true){
                System.out.println("t1");
            }
        }
    }
    static class T2 implements Runnable{
        @Override
        public void run() {
            try {
                while(true){
                    System.out.println("t2");
                    Thread.sleep(1000);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    public static void main(String[] args) {
        new Thread(new T1()).start();
        new Thread(new T2()).start();
        new Thread(new T2()).start();
    }
}

输入命令jps(jps是jdk自带的工具,配置好了环境变量即可使用)

[no1@localhost ~]$ jps
8908 1.jar
8924 Jps

可以看到有1.jar 在运行,进程ID是8908

输入pidstat命令查看进程信息 , -p 进程ID -u表示对cpu的监控, 1 和 2 代表每秒钟采集一次,一共采集二次.

[no1@localhost ~]$ pidstat -p 8908 -u 1 2
Linux 3.10.0-514.el7.x86_64 (localhost.localdomain)     20171113日     _x86_64_    (2 CPU)

100124秒   UID       PID    %usr %system  %guest    %CPU   CPU  Command
1001251000      8908   19.00   27.00    0.00   46.00     1  java
1001261000      8908   24.00   27.00    0.00   51.00     1  java
平均时间:  1000      8908   21.50   27.00    0.00   48.50     -  java

更进一步使用pidstat命令查看线程信息.

[no1@localhost ~]$ pidstat -p 8908 -u 1 2 -t
Linux 3.10.0-514.el7.x86_64 (localhost.localdomain)     20171113日     _x86_64_    (2 CPU)

100204秒   UID      TGID       TID    %usr %system  %guest    %CPU   CPU  Command
1002051000      8908         -   21.00   27.00    0.00   48.00     1  java
1002051000         -      8908    0.00    0.00    0.00    0.00     1  |__java
1002051000         -      8909    0.00    0.00    0.00    0.00     1  |__java
1002051000         -      8910    0.00    0.00    0.00    0.00     0  |__java
1002051000         -      8911    0.00    0.00    0.00    0.00     1  |__java
1002051000         -      8912    0.00    0.00    0.00    0.00     0  |__java
1002051000         -      8913    0.00    0.00    0.00    0.00     0  |__java
1002051000         -      8914    0.00    0.00    0.00    0.00     0  |__java
1002051000         -      8915    0.00    0.00    0.00    0.00     0  |__java
1002051000         -      8916    0.00    0.00    0.00    0.00     1  |__java
1002051000         -      8917    0.00    0.00    0.00    0.00     0  |__java
1002051000         -      8918    0.00    0.00    0.00    0.00     0  |__java
1002051000         -      8919    1.00    0.00    0.00    1.00     1  |__java
1002051000         -      8920   21.00   26.00    0.00   47.00     1  |__java
1002051000         -      8921    0.00    0.00    0.00    0.00     1  |__java
1002051000         -      8922    0.00    0.00    0.00    0.00     1  |__java

100205秒   UID      TGID       TID    %usr %system  %guest    %CPU   CPU  Command
1002061000      8908         -   26.00   24.00    0.00   50.00     1  java
1002061000         -      8908    0.00    0.00    0.00    0.00     1  |__java
1002061000         -      8909    0.00    0.00    0.00    0.00     1  |__java
1002061000         -      8910    0.00    0.00    0.00    0.00     0  |__java
1002061000         -      8911    0.00    0.00    0.00    0.00     0  |__java
1002061000         -      8912    0.00    0.00    0.00    0.00     0  |__java
1002061000         -      8913    0.00    0.00    0.00    0.00     0  |__java
1002061000         -      8914    0.00    0.00    0.00    0.00     0  |__java
1002061000         -      8915    0.00    0.00    0.00    0.00     0  |__java
1002061000         -      8916    0.00    0.00    0.00    0.00     1  |__java
1002061000         -      8917    0.00    0.00    0.00    0.00     0  |__java
1002061000         -      8918    0.00    0.00    0.00    0.00     0  |__java
1002061000         -      8919    0.00    0.00    0.00    0.00     1  |__java
1002061000         -      8920   26.00   24.00    0.00   50.00     1  |__java
1002061000         -      8921    0.00    0.00    0.00    0.00     1  |__java
1002061000         -      8922    0.00    0.00    0.00    0.00     1  |__java

平均时间:   UID      TGID       TID    %usr %system  %guest    %CPU   CPU  Command
平均时间:  1000      8908         -   23.50   25.50    0.00   49.00     -  java
平均时间:  1000         -      8908    0.00    0.00    0.00    0.00     -  |__java
平均时间:  1000         -      8909    0.00    0.00    0.00    0.00     -  |__java
平均时间:  1000         -      8910    0.00    0.00    0.00    0.00     -  |__java
平均时间:  1000         -      8911    0.00    0.00    0.00    0.00     -  |__java
平均时间:  1000         -      8912    0.00    0.00    0.00    0.00     -  |__java
平均时间:  1000         -      8913    0.00    0.00    0.00    0.00     -  |__java
平均时间:  1000         -      8914    0.00    0.00    0.00    0.00     -  |__java
平均时间:  1000         -      8915    0.00    0.00    0.00    0.00     -  |__java
平均时间:  1000         -      8916    0.00    0.00    0.00    0.00     -  |__java
平均时间:  1000         -      8917    0.00    0.00    0.00    0.00     -  |__java
平均时间:  1000         -      8918    0.00    0.00    0.00    0.00     -  |__java
平均时间:  1000         -      8919    0.50    0.00    0.00    0.50     -  |__java
平均时间:  1000         -      8920   23.50   25.00    0.00   48.50     -  |__java
平均时间:  1000         -      8921    0.00    0.00    0.00    0.00     -  |__java
平均时间:  1000         -      8922    0.00    0.00    0.00    0.00     -  |__java

可以看到线程id 8920 的线程占用的cpu很高。

通过jstack工具查看(jstack是jdk自带的工具,配置jdk环境变量即可使用)

[no1@localhost ~]$ jstack -l 8908 > /home/no1/temp.txt

查看temp内容

2017-11-13 10:09:16
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.151-b12 mixed mode):

"Attach Listener" #12 daemon prio=9 os_prio=0 tid=0x00007f40a4001000 nid=0x2310 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
    - None

"DestroyJavaVM" #11 prio=5 os_prio=0 tid=0x00007f40d4008800 nid=0x22cd waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
    - None

"Thread-2" #10 prio=5 os_prio=0 tid=0x00007f40d418d000 nid=0x22da waiting on condition [0x00007f40a95d0000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
    at java.lang.Thread.sleep(Native Method)
    at HoldCpuMain$T2.run(HoldCpuMain.java:17)
    at java.lang.Thread.run(Thread.java:748)

   Locked ownable synchronizers:
    - None

"Thread-1" #9 prio=5 os_prio=0 tid=0x00007f40d418b800 nid=0x22d9 waiting on condition [0x00007f40a96d1000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
    at java.lang.Thread.sleep(Native Method)
    at HoldCpuMain$T2.run(HoldCpuMain.java:17)
    at java.lang.Thread.run(Thread.java:748)

   Locked ownable synchronizers:
    - None

"Thread-0" #8 prio=5 os_prio=0 tid=0x00007f40d418a000 nid=0x22d8 runnable [0x00007f40a97d2000]
   java.lang.Thread.State: RUNNABLE
    at java.io.FileOutputStream.writeBytes(Native Method)
    at java.io.FileOutputStream.write(FileOutputStream.java:326)
    at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
    at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
    - locked <0x00000000e380dd60> (a java.io.BufferedOutputStream)
    at java.io.PrintStream.write(PrintStream.java:482)
    ...
    ...
    ...

可以看到Thread-0的 nid(Native id) 是 0x22d8, 0x 表示 16进制 , 22d8十六进制转成十进制 正好是 8920也就是线程上面pidstat检测出来的那个线程ID.

检测io

编写下面大量使用IO的程序,打成可运行jar包(命名:2.jar) 进行执行

import java.io.FileInputStream;
import java.io.FileOutputStream;

public class HoldIOMain {
    static class T1 implements Runnable{
        @Override
        public void run() {
            try {
                while(true){
                    FileOutputStream fos = new FileOutputStream("temp");
                    for(int i = 0 ; i < 100000 ;i ++){
                        fos.write(i);//大量的写
                    }
                    fos.flush();
                    fos.close();
                    FileInputStream fis = new FileInputStream("temp");
                    int b = 0;
                    while((b=fis.read()) != -1){//大量的读

                    }
                    fis.close();
                    b = 0;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    static class T2 implements Runnable{
        @Override
        public void run() {
            try {
                while(true){
                    Thread.sleep(1000);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    public static void main(String[] args) {
        new Thread(new T1()).start();
        new Thread(new T2()).start();
        new Thread(new T2()).start();
    }
}

同样jps查看 Java执行程序,发现9415进程ID 是执行的 2.jar

[no1@localhost ~]$ jps
9430 Jps
9415 2.jar

查看2.jar的进程io使用情况

[no1@localhost ~]$ pidstat -p 9415 -d 1 2
Linux 3.10.0-514.el7.x86_64 (localhost.localdomain)     20171113日     _x86_64_    (2 CPU)

105601UID       PID   kB_rd/s   kB_wr/s kB_ccwr/s  Command
1056021000      9415      0.00    840.00      0.00  java
1056031000      9415      0.00    812.00     20.00  java
平均时间:  1000      9415      0.00    826.00     10.00  java

查看更加详细的 线程使用情况

[no1@localhost ~]$ pidstat -p 9415 -d 1 2 -t
Linux 3.10.0-514.el7.x86_64 (localhost.localdomain)     20171113日     _x86_64_    (2 CPU)

105640秒   UID      TGID       TID   kB_rd/s   kB_wr/s kB_ccwr/s  Command
1056411000      9415         -      0.00    896.00      0.00  java
1056411000         -      9415      0.00      0.00      0.00  |__java
1056411000         -      9416      0.00      0.00      0.00  |__java
1056411000         -      9417      0.00      0.00      0.00  |__java
1056411000         -      9418      0.00      0.00      0.00  |__java
1056411000         -      9419      0.00      0.00      0.00  |__java
1056411000         -      9420      0.00      0.00      0.00  |__java
1056411000         -      9421      0.00      0.00      0.00  |__java
1056411000         -      9422      0.00      0.00      0.00  |__java
1056411000         -      9423      0.00      0.00      0.00  |__java
1056411000         -      9424      0.00      0.00      0.00  |__java
1056411000         -      9425      0.00      0.00      0.00  |__java
1056411000         -      9426      0.00      0.00      0.00  |__java
1056411000         -      9427      0.00    892.00      0.00  |__java
1056411000         -      9428      0.00      0.00      0.00  |__java
1056411000         -      9429      0.00      0.00      0.00  |__java

105641秒   UID      TGID       TID   kB_rd/s   kB_wr/s kB_ccwr/s  Command
1056421000      9415         -      0.00    836.00      0.00  java
1056421000         -      9415      0.00      0.00      0.00  |__java
1056421000         -      9416      0.00      0.00      0.00  |__java
1056421000         -      9417      0.00      0.00      0.00  |__java
1056421000         -      9418      0.00      0.00      0.00  |__java
1056421000         -      9419      0.00      0.00      0.00  |__java
1056421000         -      9420      0.00      0.00      0.00  |__java
1056421000         -      9421      0.00      0.00      0.00  |__java
1056421000         -      9422      0.00      0.00      0.00  |__java
1056421000         -      9423      0.00      0.00      0.00  |__java
1056421000         -      9424      0.00      0.00      0.00  |__java
1056421000         -      9425      0.00      0.00      0.00  |__java
1056421000         -      9426      0.00      0.00      0.00  |__java
1056421000         -      9427      0.00    836.00      0.00  |__java
1056421000         -      9428      0.00      0.00      0.00  |__java
1056421000         -      9429      0.00      0.00      0.00  |__java

平均时间:   UID      TGID       TID   kB_rd/s   kB_wr/s kB_ccwr/s  Command
平均时间:  1000      9415         -      0.00    866.00      0.00  java
平均时间:  1000         -      9415      0.00      0.00      0.00  |__java
平均时间:  1000         -      9416      0.00      0.00      0.00  |__java
平均时间:  1000         -      9417      0.00      0.00      0.00  |__java
平均时间:  1000         -      9418      0.00      0.00      0.00  |__java
平均时间:  1000         -      9419      0.00      0.00      0.00  |__java
平均时间:  1000         -      9420      0.00      0.00      0.00  |__java
平均时间:  1000         -      9421      0.00      0.00      0.00  |__java
平均时间:  1000         -      9422      0.00      0.00      0.00  |__java
平均时间:  1000         -      9423      0.00      0.00      0.00  |__java
平均时间:  1000         -      9424      0.00      0.00      0.00  |__java
平均时间:  1000         -      9425      0.00      0.00      0.00  |__java
平均时间:  1000         -      9426      0.00      0.00      0.00  |__java
平均时间:  1000         -      9427      0.00    864.00      0.00  |__java
平均时间:  1000         -      9428      0.00      0.00      0.00  |__java
平均时间:  1000         -      9429      0.00      0.00      0.00  |__java

9427 线程id 使用情况,同样可以通过jstack工具 验证,Thread-0 nid 0x24d3转换成十进制等于 9427
jvm学习记录--07 性能监控操作系统篇_第3张图片

检测内存

检测内存 通过-r 命令即可。

window系统监控工具

任务管理器

jvm学习记录--07 性能监控操作系统篇_第4张图片
可以通过查看 添加更多的列,查看每个进程使用情况

jvm学习记录--07 性能监控操作系统篇_第5张图片

查看网络使用情况

资源监视器

jvm学习记录--07 性能监控操作系统篇_第6张图片

Process Explorer

jvm学习记录--07 性能监控操作系统篇_第7张图片

可以代替任何window系统自带的性能监测工具

pslist命令行工具

pslist是window平台下的一款命令行工具。

百科说明:https://baike.baidu.com/item/pslist/9879691?fr=aladdin

你可能感兴趣的:(java虚拟机)