性能调优-------(六)内存使用率高,5分钟如何快速解决dump文件分析
问题:
内存使用率88%高于80%报警。
原因:
指标含义:内存使用率百分比(%)。
指标解释:容器的内存使用率是读取物理机cgroup下面的文件的,获取的是整个容器的内存使用率并不是针对某个程序。物理机内存使用率和使用free命令计算结果是一致的。物理机和容器两者内存计算数据是独立的
解决步骤:
1、查看哪些应用占用内存比较大
查看哪几个进程内存占用最高:top -c,输入大写M,以内存使用率从高到低排序
2、先通过jmap -heap 进程id 命令排除是由于堆分配内存问题。得到如下结果
Attaching to process ID 542287, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.20-b23
using thread-local object allocation.
Garbage-First (G1) GC with 43 thread(s)
//堆配置信息
Heap Configuration:
//指定 jvm heap 在使用率小于 n 的情况下 ,heap 进行收缩 ,Xmx==Xms 的情况下无效 , 如
MinHeapFreeRatio = 40
//指定 jvm heap 在使用率大于 n 的情况下 ,heap 进行扩张 ,Xmx==Xms 的情况下无效 , 如
MaxHeapFreeRatio = 70
//最大堆空间
MaxHeapSize = 5393874944 (5144.0MB)
//设置Yong Generation的初始值大小,一般情况下,不允许-XX:Newratio值小于1,即Old要比Yong大。
NewSize = 1363144 (1.2999954223632812MB)
//设置Yong Generation的最大值大小
MaxNewSize = 3235905536 (3086.0MB)
OldSize = 5452592 (5.1999969482421875MB)
//设置年轻代和老年代的比例,默认情况下,此选项为2
NewRatio = 2
//默认eden空间大小和survivor空间大小的比,默认情况下为8
SurvivorRatio = 8
//初始化元空间大小,控制gc阀值,gc后动态增加或者降低元空间大小,默认情况下平台的不同,步长为12-20M
MetaspaceSize = 209715200 (200.0MB)
//默认1G,这个参数主要是设置Klass Metaspace的大小,不过这个参数设置了也不一定起作用,前提是能开启压缩指针,假如-Xmx超过了32G,压缩指针是开启不来的。如果有Klass Metaspace,那这块内存是和Heap连着的。
CompressedClassSpaceSize = 1073741824 (1024.0MB)
//为类元数据分配的最大空间量
MaxMetaspaceSize = 536870912 (512.0MB)
//堆内存中一个Region的大小可以通过-XX:G1HeapRegionSize参数指定,大小区间只能是1M、2M、4M、8M、16M和32M,总之是2的幂次方,如果G1HeapRegionSize为默认值,则在堆初始化时计算Region的实践大小
G1HeapRegionSize = 2097152 (2.0MB)
//堆的使用信息
Heap Usage:
G1 Heap:
//区域数量
regions = 2572
//堆内存大小
capacity = 5393874944 (5144.0MB)
//已经使用了
used = 3216639400 (3067.62638092041MB)
//空闲着的堆内存
free = 2177235544 (2076.37361907959MB)
59.63503850933923% used
以下同理
G1 Young Generation:
Eden Space:
regions = 425
capacity = 2650800128 (2528.0MB)
used = 891289600 (850.0MB)
free = 1759510528 (1678.0MB)
33.62341772151899% used
Survivor Space:
regions = 1
capacity = 2097152 (2.0MB)
used = 2097152 (2.0MB)
free = 0 (0.0MB)
100.0% used
G1 Old Generation:
regions = 1109
capacity = 2740977664 (2614.0MB)
used = 2323252648 (2215.62638092041MB)
free = 417725016 (398.37361907958984MB)
84.75999927009985% used
35394 interned Strings occupying 3871104 bytes.
3、找到最耗内存的对象
jmap -histo 进程ID(带上:live则表示先进行一次FGC再统计,如jmap -histo:live 进程ID)
可以看到上面最大的实例进程 将近30M。
4、导出内存转储快照:
4.1、通过java进程命令定位 系统进程并使用jmap工具dump文件。
ps -ef | grep java
生成dump文件的命令:
jmap -dump:format=b,file=20181218.dump 16048
file后面的是自定义的文件名,最后的数字是进程的pid。
4.2、使用jvisualvm来分析dump文件:
jvisualvm是JDK自带的Java性能分析工具,在JDK的bin目录下,文件名就叫jvisualvm.exe。
jvisualvm可以监控本地、远程的java进程,实时查看进程的cpu、堆、线程等参数,对java进程生成dump文件,并对dump文件进行分析。
假设我现在下载下来的是txt文件也可以直接扔给jvisualvm来分析。
4.3、使用方式:直接双击打开jvisualvm.exe,点击文件->装入,在文件类型那一栏选择堆,选择要分析的dump文件,打开。
导入文件以后界面如下图:
可以看到,dump文件里记录的堆中的实例,总大小大概5392M左右,(用第一行的实例大小除以百分比就能算出来)
4.4、现在看堆转储的线程问题
每一个部分的含义如下:
“http-nio-1601-Acceptor-0” 线程名称
daemon 线程的类型
prio=5 线程的优先级别
tid=290 线程ID
RUNNABLE 线程当前的状态
4.5、线程当前的状态是我们主要关注的内容。
dump文件中描述的线程状态
runnable:运行中状态,在虚拟机内部执行,可能已经获取到了锁,可以观察是否有locked字样。
blocked:被阻塞并等待锁的释放。
wating:处于等待状态,等待特定的操作被唤醒,一般停留在park(), wait(), sleep(),join() 等语句里。
time_wating:有时限的等待另一个线程的特定操作。
terminated:线程已经退出
4.6、进程的区域划分
进入区(Entry Set):等待获取对象锁,一旦对象锁释放,立即参与竞争。
拥有区(The Owner):已经获取到锁。
等待区(Wait Set):表示线程通过wait方法释放了对象锁,并在等待区等待被唤醒。
4.7、方法调用修饰
locked: 成功获取锁
waiting to lock:还未获取到锁,在进入去等待;
waiting on:获取到锁之后,又释放锁,在等待区等待;
4.8、OQL(对象查询语言)
如果需要根据某些条件来过滤或查询堆的对象,比如现在我们查询下系统中类加载器一共有几种?
4.9、引导计数
引导类 (即 JVM 在未使用任何 java.lang.ClassLoader 实例的情况下加载的 Java 平台类) 的计数
其余展示的与名称一样
5、统计进程打开的句柄数:ls /proc/进程ID/fd |wc -l
6、统计进程打开的线程数:ls /proc/进程ID/task |wc -l
7、使用jstat查看进程的内存使用情况
jstat [Options] vmid [interval] [count]
Options,选项,我们一般使用 -gcutil 查看gc情况
vmid,VM的进程号,即当前运行的java进程号
interval,间隔时间,单位为秒或者毫秒
count,打印次数,如果缺省则打印无数次
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0.00 100.00 32.20 7.05 48.98 95.35 102490 10125.674 1 39.100 10164.775
0.00 100.00 32.57 7.05 48.98 95.35 102490 10125.674 1 39.100 10164.775
0.00 100.00 32.94 7.05 48.98 95.35 102490 10125.674 1 39.100 10164.775
0.00 100.00 33.31 7.05 48.98 95.35 102490 10125.674 1 39.100 10164.775
0.00 100.00 33.62 7.05 48.98 95.35 102490 10125.674 1 39.100 10164.775
S0C:年轻代中第一个survivor(幸存区)的容量 (字节)
S1C:年轻代中第二个survivor(幸存区)的容量 (字节)
S0U:年轻代中第一个survivor(幸存区)目前已使用空间 (字节)
S1U:年轻代中第二个survivor(幸存区)目前已使用空间 (字节)
EC:年轻代中Eden(伊甸园)的容量 (字节)
EU:年轻代中Eden(伊甸园)目前已使用空间 (字节)
OC:Old代的容量 (字节)
OU:Old代目前已使用空间 (字节)
PC:Perm(持久代)的容量 (字节)
PU:Perm(持久代)目前已使用空间 (字节)
YGC:从应用程序启动到采样时年轻代中gc次数
YGCT:从应用程序启动到采样时年轻代中gc所用时间(s)
FGC:从应用程序启动到采样时old代(全gc)gc次数
FGCT:从应用程序启动到采样时old代(全gc)gc所用时间(s)
GCT:从应用程序启动到采样时gc用的总时间(s)
NGCMN:年轻代(young)中初始化(最小)的大小 (字节)
NGCMX:年轻代(young)的最大容量 (字节)
NGC:年轻代(young)中当前的容量 (字节)
OGCMN:old代中初始化(最小)的大小 (字节)
OGCMX:old代的最大容量 (字节)
OGC:old代当前新生成的容量 (字节)
PGCMN:perm代中初始化(最小)的大小 (字节)
PGCMX:perm代的最大容量 (字节)
PGC:perm代当前新生成的容量 (字节)
S0:年轻代中第一个survivor(幸存区)已使用的占当前容量百分比
S1:年轻代中第二个survivor(幸存区)已使用的占当前容量百分比
E:年轻代中Eden(伊甸园)已使用的占当前容量百分比
O:old代已使用的占当前容量百分比
P:perm代已使用的占当前容量百分比
M:元空间中已使用的占当前容量百分比
S0CMX:年轻代中第一个survivor(幸存区)的最大容量 (字节)
S1CMX :年轻代中第二个survivor(幸存区)的最大容量 (字节)
ECMX:年轻代中Eden(伊甸园)的最大容量 (字节)
DSS:当前需要survivor(幸存区)的容量 (字节)(Eden区已满)
TT: 持有次数限制
MTT : 最大持有次数限制
8、.用jstack查看一下
jstack pid | grep tid(线程ID) -A 30