输入以下命令
top
输出内容如下
top - 12:42:18 up 17:58, 1 user, load average: 0.02, 0.05, 0.05
Tasks: 210 total, 1 running, 209 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.0 us, 0.1 sy, 0.0 ni, 99.8 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 8008100 total, 3337016 free, 3381284 used, 1289800 buff/cache
KiB Swap: 8257532 total, 8257532 free, 0 used. 4190364 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
5310 root 20 0 3834388 955156 14744 S 1.0 11.9 8:42.44 java
868 root 20 0 115408 984 704 S 0.3 0.0 0:00.48 ksmtuned
3134 devbase 20 0 6487524 838328 16216 S 0.3 10.5 7:14.17 java
4445 root 20 0 4059928 160240 11852 S 0.3 2.0 1:23.55 java
1 root 20 0 194088 7292 4204 S 0.0 0.1 0:04.00 systemd
可以把输出内容分成两块来看
一块是概要信息
top - 12:42:18 up 17:58, 1 user, load average: 0.02, 0.05, 0.05
Tasks: 210 total, 1 running, 209 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.0 us, 0.1 sy, 0.0 ni, 99.8 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 8008100 total, 3337016 free, 3381284 used, 1289800 buff/cache
KiB Swap: 8257532 total, 8257532 free, 0 used. 4190364 avail Mem
一块是每个进程详细信息
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
5310 root 20 0 3834388 955156 14744 S 1.0 11.9 8:42.44 java
868 root 20 0 115408 984 704 S 0.3 0.0 0:00.48 ksmtuned
3134 devbase 20 0 6487524 838328 16216 S 0.3 10.5 7:14.17 java
4445 root 20 0 4059928 160240 11852 S 0.3 2.0 1:23.55 java
1 root 20 0 194088 7292 4204 S 0.0 0.1 0:04.00 systemd
接下来就分别进行介绍
参数 | 含义 | 备注 |
---|---|---|
top - 12:42:18 | 系统当前时间 | 可以不用看手机时间啦 |
up 17:58 | 系统运行时间 | 看从开机到现在这台电脑跑了多久,显得这台电脑劳苦功高 |
1 user | 当前登录用户数:1个 | 看看有没有其他人登着 |
load average: 0.02, 0.05, 0.05 | 系统平均负载(3个值分别为1分钟/5分钟/15分钟)的平均负载 | 看看刚刚一段时间,电脑运行的累不累,负载越高越辛苦 |
参数 | 含义 |
---|---|
Tasks: 210 total | 总进程数 |
1 running | 1个进程在运行 |
209 sleeping | 209进程个在睡眠(好家伙) |
0 stopped | 0个进程处于停止 |
0 zombie | 没有僵尸进程 |
参数 | 含义 | 缩写 |
---|---|---|
0.0 us | 用户空间占用CPU百分比 | user mode |
0.1 sy | 内核空间占用CPU百分比 | system mode |
0.0 ni | 用户进程空间内改变过优先级的进程占用CPU百分比 | low priority user mode (nice) |
99.8 id | 空闲CPU百分比 99.8% (真就偷懒呗) | idle task |
0.0 wa | 等待IO的CPU时间百分比 | I/O waiting |
0.0 hi | 硬件中断时间百分比 | servicing IRQs |
0.0 si | 软件中断 时间百分比 | servicing soft IRQs |
0.0 st | 实时时间百分比 | steal (time given to other DomU instances) |
参数 | 含义 |
---|---|
KiB Mem : 8008100 total | 物理内存总量(KB) |
3337016 free | 空闲内存总量(KB) |
3381284 used | 使用的物理内存总量(KB) |
1289800 buff/cache | 用作内核缓存的内存量(KB) |
参数 | 含义 |
---|---|
KiB Swap: 8257532 total | 交换区总量(KB) |
8257532 free | 空闲交换区总量(KB) |
0 used | 使用的交换区总量(KB) |
4190364 avail Mem | 可用的内存(KB) |
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
5310 root 20 0 3834388 955156 14744 S 1.0 11.9 8:42.44 java
868 root 20 0 115408 984 704 S 0.3 0.0 0:00.48 ksmtuned
3134 devbase 20 0 6487524 838328 16216 S 0.3 10.5 7:14.17 java
4445 root 20 0 4059928 160240 11852 S 0.3 2.0 1:23.55 java
1 root 20 0 194088 7292 4204 S 0.0 0.1 0:04.00 systemd
简写 | 全称 | 含义 |
---|---|---|
PID | Process Id | 进程ID |
USER | User Name | 当前进程运行的用户 |
PR | Priority | 优先级 |
NI | Nice Value | 负值表示高优先级,正值表示低优先级 |
VIRT | Virtual Image | 进程使用的虚拟内存总量(KB)。VIRT=SWAP+RES |
RES | Resident size | 进程使用的、未被换出的物理内存大小(KB)。RES=CODE+DATA |
SHR | Shared Mem size | 共享内存大小,单位(KB) |
S | Status | 进程状态(D|R|S|T|Z),可以看后面那进程张状态表 |
%CPU | cpu | CPU占用百分比 |
%MEM | memory | 内存占用百分比 |
TIME+ | TIME | 系统运行时间 |
COMMAND | COMMAND | 运行的程序 |
该表最值得看的就是%CPU和%MEM ,可以看是否内存占用过高或者cpu占用过高。
若cpu占用过高,可能是空轮循,或者发生了频繁的垃圾回收,或者程序访问压力过大
若内存占用过高,可能存在内存泄漏
状态值 | 含义 | 全称 |
---|---|---|
R | 运行 | running |
D | 不可中断的睡眠状态 | uninterruptible sleep |
S | 睡眠 | sleeping |
T | 跟踪/停止 | traced or stopped |
Z | 僵尸进程 | zombie |
free -mh
命令组成 | 含义 |
---|---|
free | 查看内存的命令 |
m | MB,表示转换为单位MB进行显示 |
h | human,表示以人类可读的方式显示 |
输出内容如下
total used free shared buff/cache available
Mem: 7.6G 3.2G 3.2G 129M 1.2G 4.0G
Swap: 7.9G 0B 7.9G
具体含义如下
参数 | 含义 |
---|---|
total | 总内存 |
used | 使用内存 |
free | 空闲内存 |
shared | 共享内存 |
buff/cache | 缓冲区内存 |
available | 可用内存 |
df -h
输出内容
文件系统 容量 已用 可用 已用% 挂载点
devtmpfs 3.9G 0 3.9G 0% /dev
tmpfs 3.9G 0 3.9G 0% /dev/shm
tmpfs 3.9G 130M 3.7G 4% /run
tmpfs 3.9G 0 3.9G 0% /sys/fs/cgroup
可以看磁盘是否出现沾满的情况
jps
#或者
jps -V
显示两列,分别是进程ID和启动类的名称
33809 RemoteJdbcServer
31428 RemoteMavenServer36
31286
34573 Launcher
34574 CartoonApplication
35887 Jps
因为本次运行的服务是CartoonApplication,所以进程id为34574
jstat -gc 34574 2000
命令及参数 | 含义 |
---|---|
jstat | jdk自带的工具 |
-gc | 查看gc的情况(还可以查看class/compile/gcold) |
34574 | 进程ID,本次要查看的进程ID为34574,生产上要根据上一步的jps获得 |
2000 | 每隔2000毫秒打印一次 |
返回的结果如下所示:
其中
参数 | 全称 | 释义 |
---|---|---|
S0C | Current survivor space 0 capacity (KB). | S0的当前总容量(KB) |
S1C | Current survivor space 1 capacity (KB). | S1的当前总容量(KB) |
S0U | Survivor space 0 utilization (KB). | S0的利用情况(KB) |
S1U | Survivor space 1 utilization (KB). | S1的利用情况(KB) |
EC | Current eden space capacity (KB). | 伊甸园的当前总容量(KB) |
EU | Eden space utilization (KB). | 伊甸园的利用情况(KB) |
OC | Current old space capacity (KB). | 老年代的当前总容量(KB) |
OU | Old space utilization (KB). | 老年代的利用情况(KB) |
PC | Current permanent space capacity (KB). | 永久代的当前总容量(KB) |
PU | Permanent space utilization (KB). | 永久代的利用情况(KB) |
YGC | Number of young generation GC Events. | YoungGC的次数(KB) |
YGCT | Young generation garbage collection time. | YoungGC的时间 |
FGC | Number of full GC events. | FullGC次数 |
FGCT | Full garbage collection time. | FullGC时间 |
GCT | Total garbage collection time. | GC总时间 |
这里感觉官方的说法并不好,因为实际上Current capacity其实应该翻译为总容量的意思。
而utilization不应该翻译为利用率,而应该是使用情况。因为单位是KB。
我们在这个过程中最应该关心的就是 FGC 的次数
如果说我们每2秒打印一次,它的FullGC就增加1次。这就说明在这个过程中发生了频繁的GC
从上图可得,每2秒打印,它的 FGC 一直保持为2,说明从系统运行到现在为止总共只发生了2次GC
jstack 34574 > jstack.log
参数或命令 | 含义 |
---|---|
jstack | jdk自带命令,可以查看栈现场的情况 |
34574 | 进程ID,本次要查看的进程ID为34574,生产上要根据上一步的jps获得 |
> | 重定向 |
jstack.log | 重定向到当前目录下的jstack.log,若没有则生成 |
对刚刚生成的栈现场文件进行分析,查看有多少个线程
grep 'java.lang.Thread.State' jstack.log | wc -l
参数或命令 | 含义 |
---|---|
grep | 匹配并过滤出 |
‘java.lang.Thread.State’ | 匹配并过滤出java.lang.Thread.State的文本内容 |
jstack.log | 被过滤的文件 |
| | 管道,用于将过滤出的结果传递给下一个命令 |
wc | word count 统计 |
-l | 按行统计,统计行数 |
输出结果
83
说明当前程序总共在跑的线程数有83个。事实上,83个线程也不是很多
查看线程是否有异样
grep -A 1 'java.lang.Thread.State' jstack.log | grep -v 'java.lang.Thread.State' | sort | uniq -c |sort -n
参数命令
参数 | 含义 |
---|---|
grep -A 1 ‘java.lang.Thread.State’ | 匹配 java.lang.Thread.State并过滤文件,并关联出对应上下各1行 |
jstack.log | 被匹配的文件 |
| | 管道,将刚刚的输出结果作为输入 |
grep -v ‘java.lang.Thread.State’ | 匹配不含java.lang.Thread.State的内容(这样只剩下上下各一行) |
sort | 将所有行按照字典序排序 |
uniq -c | 去除排序后相连重复的行 |
sort -n | 以数字的形式排序 |
输出
1 at java.lang.Thread.sleep(Native Method)
1 at java.net.PlainSocketImpl.socketAccept(Native Method)
1 at java.net.SocketInputStream.socketRead0(Native Method)
1 at sun.nio.ch.ServerSocketChannelImpl.accept0(Native Method)
3 at sun.nio.ch.KQueueArrayWrapper.kevent0(Native Method)
11
14 at java.lang.Object.wait(Native Method)
51 at sun.misc.Unsafe.park(Native Method)
82 --
看输出没有任何异样
jmap -dump:format=b,file=heap.log 34574
参数或命令 | 含义 |
---|---|
jmap | jdk自带命令,可以查看堆现场的情况 |
-dump:format=b | 以二进制的形式输出堆 |
file=heap.log | 输出文件的文件名为heap.log |
34574 | 进程ID,本次要查看的进程ID为34574,生产上要根据上一步的jps获得 |
服务器上没有好的可视化分析工具,必须把文件下载到本地
查看文件大小
ls -lh
显示内容,文件大概219MB
-rw------- 1 admin staff 219M 8 15 15:09 heap.log
但是生产上的堆文件可能很大,所以我们需要先对文件内容进行压缩,然后再进行传输
gzip -6 heap.log
以下是参数的命令
参数或命令 | 含义 |
---|---|
gzip | 压缩命令 |
-6 | 用于指定压缩等级,-1 压缩等级最低,压缩比最差;-9 压缩比最高。默认压缩比是 -6 |
heap.log | 被压缩的文件名 |
稍等片刻压缩完毕
ls -lh
我们发现源文件消失,压缩后的文件出现,只有48MB,压缩到了原来的21%,非常方便传输
-rw------- 1 admin staff 48M 8 15 15:09 heap.log.gz
然后把文件转移到本地后再解压
gunzip heap.log.gz
MAT 是分析 Java 堆内存的利器,使用它打开我们的堆文件(将文件后缀改为 .hprof), 它会提示我们要分析的种类。
大对象情况,看起来好像没有,最大的对象也就只有2.4MB。
查看每个类的情况
最大的是char[],总共有7万多个对象,内存占到7MB左右
看起来都很正常。
因为这是本地为了测试jdk的工具,下了正常应用程序的一个堆。为了测试才打开的。事实上说明该本地应用程序确实没有什么问题
但是思路是一样的,就是通过一步步的命令,层层排查,抽丝拨茧。
你如果有遇到什么线上排查成功的例子,也可以在评论区分析给大家
https://www.toutiao.com/i6698492096132678152/?tt_from=weixin&utm_campaign=client_share&wxshare_count=1×tamp=1628998274&app=news_article&utm_source=weixin&utm_medium=toutiao_android&use_new_style=1&req_id=202108151131140101512130844D7398DF&share_token=39c48a51-1e0e-49ce-8095-335479801aa8&group_id=6698492096132678152&wid=1628998991385