java内存泄漏排查

java内存泄漏排查

查看cpu的实时运行情况

输入以下命令

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   

接下来就分别进行介绍

概要信息

概要信息第1行参数
参数 含义 备注
top - 12:42:18 系统当前时间 可以不用看手机时间啦
up 17:58 系统运行时间 看从开机到现在这台电脑跑了多久,显得这台电脑劳苦功高
1 user 当前登录用户数:1个 看看有没有其他人登着
load average: 0.02, 0.05, 0.05 系统平均负载(3个值分别为1分钟/5分钟/15分钟)的平均负载 看看刚刚一段时间,电脑运行的累不累,负载越高越辛苦
概要信息第2行参数
参数 含义
Tasks: 210 total 总进程数
1 running 1个进程在运行
209 sleeping 209进程个在睡眠(好家伙)
0 stopped 0个进程处于停止
0 zombie 没有僵尸进程
概要信息第3行参数
参数 含义 缩写
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)
概要信息第4行参数
参数 含义
KiB Mem : 8008100 total 物理内存总量(KB)
3337016 free 空闲内存总量(KB)
3381284 used 使用的物理内存总量(KB)
1289800 buff/cache 用作内核缓存的内存量(KB)
概要信息第5行参数
参数 含义
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

可以看磁盘是否出现沾满的情况

查看当前程序的进行ID

jps
#或者
jps -V

显示两列,分别是进程ID和启动类的名称

33809 RemoteJdbcServer
31428 RemoteMavenServer36
31286 
34573 Launcher
34574 CartoonApplication
35887 Jps

因为本次运行的服务是CartoonApplication,所以进程id为34574

查看进程的GC回收状态

jstat -gc 34574 2000
命令及参数 含义
jstat jdk自带的工具
-gc 查看gc的情况(还可以查看class/compile/gcold)
34574 进程ID,本次要查看的进程ID为34574,生产上要根据上一步的jps获得
2000 每隔2000毫秒打印一次

返回的结果如下所示:

java内存泄漏排查_第1张图片

其中

参数 全称 释义
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软件进行堆内存分析

MAT 是分析 Java 堆内存的利器,使用它打开我们的堆文件(将文件后缀改为 .hprof), 它会提示我们要分析的种类。

java内存泄漏排查_第2张图片

大对象情况,看起来好像没有,最大的对象也就只有2.4MB。

查看每个类的情况

java内存泄漏排查_第3张图片

最大的是char[],总共有7万多个对象,内存占到7MB左右

java内存泄漏排查_第4张图片

看起来都很正常。

因为这是本地为了测试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

你可能感兴趣的:(linux,cpu,java,内存泄漏,操作系统)