一、linux性能收集和统计工具
二、JAVA性能调优之jdk命令工具
一、linux性能收集和统计工具
linux在性能遇到问题时,常用的查看分析命令有
- top:能够实时显示系统各个进程的资源占用情况;
- sar:可以周期性的对内存CPU使用情况采样;
- vmstat:可统计CPU内存使用情况、swap使用情况等信息;
- iostat:提供的是详细的I/O信息;
- pidstat:可以监视进程的性能情况,也可以监视线程的情况;
下面分别介绍这几个命令参数的
1、top命令
top命令的输出分为两部分:前半部分是系统统计信息和进程统计信息,后半部分是进程区的信息
第1行是任务队列信息,从左到右依次为系统当前时间、系统运行时间、当前登录用户数。最后的load average表示系统的平均负载,即任务队列的平均长度,这3个值分别表示1分钟、5分钟、15分钟到现在的平均值。
第2行是进程统计信息,其含义从左到右表示正在运行的进程数、睡眠进程数、停止的进程数、僵户进程数。
第3行是CPU统计信息,us表示用户空间CPU占用率、Sy表示内核空间CPU 占用率、ni表示用户进程空间改变过优先级的进程CPU的占用率、id表示空闲CPU占用率、Wa表示等待输入输出的CPU时间百分比、hi表示硬件中断请求、si表示软件中断请求。
第4行是内存统计信息,其含义从左到右依次表示内存总量、已使用的内存、空闲内存、内核缓冲使用量。
第5行是交换区的统计信息,不做说明
进程区的列说明如下
列名 | 含义 |
---|---|
PID | 进程id |
USER | 进程所有者的用户名 |
PR | 优先级 |
NI | nice值。负值表示高优先级,正值表示低优先级 |
VIRT | 进程使用的虚拟内存总量,单位KB。VIRT=SWAP+RES |
RES | 进程使用的、未被换出的物理内存大小,单位KB |
S | 进程状态,D,不可中断的睡眠状态,R,运行,S,睡眠,T,跟踪停止,Z,僵尸 |
%CPU | 上次更新到现在的CPU时间占用百分比 |
%MEM | 进程使用的物理内存百分比 |
TIME+ | 进程使用的CPU时间总计,单位1/100秒 |
COMMAND | 进程名 |
top还有一些隐藏的列,在top下按F键,可以对列进行选择或者排序,top只能查看是哪一个进程占用资源较高
2、sar命令
sar [options] [ []]
interval和count分别表示采样周期(秒)和采样数量(采样几次)。options选项可以指定sar命令对哪些性能数据进行采样,
options参数列表
options选项 | 选项对应含义 |
---|---|
A | 所有报告的总和 |
u | CPU利用率 |
d | 硬盘使用报告 |
b | I/O情况 |
q | 队列长度 |
r | 内存使用统计信息 |
n | 网络信息统计 |
例:CPU使用情况sar -r 1 3
3、vmstat命令
vmstat可统计CPU内存使用情况、swap使用情况等信息,默认采样一次,也可以和sar一样设置采样频率。
参数含义列表
参数 | 各列含义 |
---|---|
Procs | r:等待运行的进程数 b:处在非中断睡眠状态的进程数 |
Memory | swpd:虚拟内存使用情况 free:空闲的内存 buff:被用来作为缓存的内存数 |
Swap | si:从磁盘交换到内存的交换页数量 SO:从内存交换到磁盘的交换页数量 |
IO | bi:发送到块设备的块数 bo:从块设备接收到的块数 |
System | in:每秒的中断数,包括时钟中断 CS:每秒的上下文切换次数 |
CPU | uS:用户CPU使用时间 sy:内核CPU系统使用时间 id:空闲时间 |
4、iostat命令
当怀疑是磁盘I/O引起的性能问题时,可以采用iostat命令排查问题。通过iostat可以快速定位系统是否产生了大
量的IO操作。
iostat可以不跟参数运行,也可以跟上详细的参数
iostat
iostat 1 3
iostat [options] [ []] options的值可以使用 iostat -help获取
列参数含义
参数 | 列含义 |
---|---|
tps | 该设备每秒的传输次数 |
kB_read/s | 每秒从设备读取的数据量 |
kB_wrtn/s | 每秒向设备写入的数据量 |
kB_read | 读取的总数据量 |
kB_wrtn | 写入的总数据量 |
KB_dscd | 每秒设备丢弃的数据量 |
5、pidstat命令
5.1 CPU监控
1、编写一个占用CPU的程序,一个占用线程,两个空闲的线程
package com.toto.cpu;
/**
* @Description: CpuUseDemo
* @Package: com.toto
* @Author gufanbiao
* @CreateTime 2024-06-05 18:41
*/
public class Cppackage com.toto.cpu;
/**
* @Description: CpuUseDemo
* @Package: com.toto
* @Author gufanbiao
* @CreateTime 2024-06-05 18:41
*/
public class CpuUseDemo {
public static class CpuUseMax implements Runnable {
@Override
public void run() {
while (true) {
double a = Math.random()*Math.random();
}
}
}
public static class CpuUseMin implements Runnable {
@Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
//throw new RuntimeException(e);
}
}
}
}
public static void main(String[] args) {
System.out.println("开启占用CPU线程");
new Thread(new CpuUseMax()).start();
System.out.println("开启两个不是那么占用线程的线程1");
new Thread(new CpuUseMin()).start();
System.out.println("开启两个不是那么占用线程的线程2");
new Thread(new CpuUseMin()).start();
}
}
uUseDemo {
public static class CpuUseMax implements Runnable {
@Override
public void run() {
while (true) {
double a = Math.random()*Math.random();
}
}
}
public static class CpuUseMin implements Runnable {
@Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
//throw new RuntimeException(e);
}
}
}
}
public static void main(String[] args) {
// 开启占用CPU线程
new Thread(new CpuUseMax()).start();
// 开启两个不是那么占用线程的线程
new Thread(new CpuUseMin()).start();
new Thread(new CpuUseMin()).start();
}
}
2、运行程序,使用jps查找java程序的pid
[root@localhost ~]# jps
71563 Jps
71548 CpuUseDemo
3、使用pidstat输出程序cpu的使用情况
[root@localhost ~]# pidstat -p 71548 -u 1 3
...
07:40:55 PM UID PID %usr %system %guest %CPU CPU Command
07:40:56 PM 0 71970 100.00 0.00 0.00 100.00 0 java
07:40:57 PM 0 71970 99.01 0.00 0.00 99.01 0 java
07:40:58 PM 0 71970 100.00 0.00 0.00 100.00 0 java
Average: 0 71970 99.67 0.00 0.00 99.67 - java
-p用于指定进程ID
-u表示对CPU使用率的监控。
1 3表示每秒钟采样一次,合计采样3次。
从输出中可以看到,该应用程序CPU占用率几乎达100%。pidstat的功能不仅仅限于观察进程信息,它可以进一步监控线程的信息。
[root@localhost ~]# pidstat -p 71970 1 3 -u -t
Linux 3.10.0-1160.el7.x86_64 (localhost.localdomain) 06/09/2024 _x86_64_ (2 CPU)
08:01:00 PM UID TGID TID %usr %system %guest %CPU CPU Command
08:01:01 PM 0 71970 - 100.00 0.00 0.00 100.00 0 java
...
08:01:01 PM 0 - 71972 0.00 0.00 0.00 0.00 0 |__GC task thread#
08:01:01 PM 0 - 71973 0.00 0.00 0.00 0.00 0 |__GC task thread#
...
08:01:01 PM 0 - 71982 100.00 0.00 0.00 100.00 0 |__Thread-0
08:01:01 PM 0 - 71983 0.00 0.00 0.00 0.00 1 |__Thread-1
08:01:01 PM 0 - 71984 0.00 0.00 0.00 0.00 1 |__Thread-2
参数-t将进程中的线程级别输出,可以明确看到是71982线程较高。
进一步使用jstack -l 71982>/opt/71982.txt,可以看到是哪段代码出的问题。
“Thread-0” #8 prio=5 os_prio=0 tid=0x00007f77e0152800 nid=0x11a6a runnable [0x00007f77cb0c7000]
java.lang.Thread.State: RUNNABLE
at com.toto.cpu.CpuUseDemo$CpuUseMax.run(CpuUseDemo.java:15)
at java.lang.Thread.run(Thread.java:750)
5.2 IO监控
IO 的监控同CPU监控类似
- 首先使用 jps 查看进程ID
- 其次使用 pidstat -p 71970 1 3 -d -t
- 再次使用 jstack 导出当前线程的堆栈信息,定位IO操作的代码
5.3 内存监控
该命令和参数,能查出内存的占用情况
pidstat -p -r 71970 1 3
6、话外篇
ps 命令不存在时
[root@localhost ~]# Jps
bash: Jps: command not found...
[root@localhost ~]# yum list *openjdk-devel*
[root@localhost ~]# yum install java-1.8.0-openjdk-devel.x86_64
查看java安装目录
执行命令,逐步寻找java安装目录
[root@localhost /]# which java
/usr/bin/java
[root@localhost /]# ls -lrt /usr/bin/java
lrwxrwxrwx. 1 root root 22 Jun 6 03:25 /usr/bin/java -> /etc/alternatives/java
[root@localhost /]# ls -lrt /etc/alternatives/java
lrwxrwxrwx. 1 root root 73 Jun 6 03:25 /etc/alternatives/java -> /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.412.b08-1.el7_9.x86_64/jre/bin/java
修改环境变量文件
[root@localhost bin]# vi /etc/profile
##JAVA_HOME配置
export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.412.b08-1.el7_9.x86_64/jre
export PATH=$JAVA_HOME/bin:$PATH
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
3.使配置生效
source /etc/profile
ot@localhost bin]# vi /etc/profile
```shell
##JAVA_HOME配置
export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.412.b08-1.el7_9.x86_64/jre
export PATH=$JAVA_HOME/bin:$PATH
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
3.使配置生效
source /etc/profile