Jmap
查看内存信息,示例个数,占用内存大小
jmap -histo $pid #查看历史生成的实例
jmap -histo:live $pid #当前存活的实例,执行过程可能会触发一次full 过程
- num:序号
- instances:实例数量
- bytes:占用空间大小
- class name:类名称 [C = char[] [S = short[] [L = int [] [B = byte[] [I = int [][]
堆信息dump:jmap -dump:format=b,file=eureka.hprof $pid #.hprof可以导入**jvisualvm**
jvm参数:
-XX:+HeapDumpOnOutOfMemoryError 内存溢出时,自动导出dump文件有可能导不出来
-XX:HeapDumapPath=./ 路径
Jstack
栈信息,线程相关的信息
可以用jvsualVm链接jvm 检查死锁,前提是远程启动是加参数
java -Dcom.sun.management.jmxremote.port=8888 -Djava.rmi.server.hostname=192.168.65.60 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -jar microservice-eureka-server.jar
PS:
-Dcom.sun.management.jmxremote.port 为远程机器的JMX端口
-Djava.rmi.server.hostname 为远程机器IPsystemctl stop firewalld #临时关闭防火墙
jstack找出占用cpu最高的线程堆栈信息
- top -p pid :显示Java进程内存信息
- 按H ,获取每个线程的内存情况
- 找到最高的tid 19664,转为16进制 0x4cd0
- jstack pid | grep -A 10 4cd0 得到最后10行,查看原因
Jinfo
jinfo -flags pid #查看正在运行的jvm 参数
jinfo -sysprops pid # 查看Java系统参数
Jstat
查看堆内存各部分的使用量,以及加载的类数量jstat -[选项] [vmid] [间隔时间毫妙] [查询次数``]
jstat -gc pid
- S0C:第一个幸存区的大小,单位KB
- S1C:第二个幸存区的大小
- S0U:第一个幸存区的使用大小
- S1U:第二个幸存区的使用大小
- EC:伊甸园区的大小
- EU:伊甸园区的使用大小
- OC:老年代大小
- OU:老年代使用大小
- MC:方法区大小(元空间)
- MU:方法区使用大小
- CCSC:压缩类空间大小
- CCSU:压缩类空间使用大小
- YGC:年轻代垃圾回收次数
- YGCT:年轻代垃圾回收消耗时间,单位s
- FGC:老年代垃圾回收次数
- FGCT:老年代垃圾回收消耗时间,单位s
- GCT:垃圾回收消耗总时间,单位s
jstat -gccapacity pid
- NGCMN:新生代最小容量
- NGCMX:新生代最大容量
- NGC:当前新生代容量
- S0C:第一个幸存区大小
- S1C:第二个幸存区的大小
- EC:伊甸园区的大小
- OGCMN:老年代最小容量
- OGCMX:老年代最大容量
- OGC:当前老年代大小
- OC:当前老年代大小
- MCMN:最小元数据容量
- MCMX:最大元数据容量
- MC:当前元数据空间大小
- CCSMN:最小压缩类空间大小
- CCSMX:最大压缩类空间大小
- CCSC:当前压缩类空间大小
- YGC:年轻代gc次数
- FGC:老年代GC次数
jstat -gcnew pid
- NGCMN:新生代最小容量
- NGCMX:新生代最大容量
- NGC:当前新生代容量
- S0CMX:最大幸存1区大小
- S0C:当前幸存1区大小
- S1CMX:最大幸存2区大小
- S1C:当前幸存2区大小
- ECMX:最大伊甸园区大小
- EC:当前伊甸园区大小
- YGC:年轻代垃圾回收次数
- FGC:老年代回收次数
jstat -gcold pid
- MC:方法区大小
- MU:方法区使用大小
- CCSC:压缩类空间大小
- CCSU:压缩类空间使用大小
- OC:老年代大小
- OU:老年代使用大小
- YGC:年轻代垃圾回收次数
- FGC:老年代垃圾回收次数
- FGCT:老年代垃圾回收消耗时间
- GCT:垃圾回收消耗总时间
jstat -gcoldcapacity pid
- OGCMN:老年代最小容量
- OGCMX:老年代最大容量
- OGC:当前老年代大小
- OC:老年代大小
- YGC:年轻代垃圾回收次数
- FGC:老年代垃圾回收次数
- FGCT:老年代垃圾回收消耗时间
- GCT:垃圾回收消耗总时间
jstat -gcmetacapacity pid
- MCMN:最小元数据容量
- MCMX:最大元数据容量
- MC:当前元数据空间大小
- CCSMN:最小压缩类空间大小
- CCSMX:最大压缩类空间大小
- CCSC:当前压缩类空间大小
- YGC:年轻代垃圾回收次数
- FGC:老年代垃圾回收次数
- FGCT:老年代垃圾回收消耗时间
- GCT:垃圾回收消耗总时间
jstat -gcutil pid
- S0:幸存1区当前使用比例
- S1:幸存2区当前使用比例
- E:伊甸园区使用比例
- O:老年代使用比例
- M:元数据区使用比例
- CCS:压缩使用比例
- YGC:年轻代垃圾回收次数
- FGC:老年代垃圾回收次数
- FGCT:老年代垃圾回收消耗时间
- GCT:垃圾回收消耗总时间
JVM运行情况的估算思路
1:先通过 jstat gc -pid 计算关键数据
每秒产生多少对象
多久s区会满,minor gc的周期,
年轻代对象增长速率
jstat -gc pid 1000 10 #每1000ms执行一次,共执行10次
观察Eden区的使用来估算每秒新增了多少对象
YoungGC 触发的频率和每次的耗时
根据Eden的大小,和增长速度,推算minor gc多久
YoungGC 的凭据耗时计算: YGCT/YGC
估算每次minor gc 有多少对象存活,和多少进入老年代
每次 youngGC eden会变小,s区,老年代会变大,这个增长的就是youngGC后存活的
据此推断老年代对象的增长速度
Full gc 触发频率和每次耗时
耗时就算: FGCT/FGC
优化的思路:每次Young GC后的存活对象小于 S区的50%,尽量都留在年轻代。
减少FullGC
案例分析
Full Gc 导致卡顿的原因
- 先查看对应应用的jvm参数
- 画出 对应的内存模型
- jstat -gc pid 查看gc前后的内存变化
计算每秒产生多少对象
多久会占满 eden ,
多久会有多少对象移至老年代,
通常是老年代引起的Full gc
-Xms1536M -Xmx1536M -Xmn512M -Xss256K -XX:SurvivorRatio=6 -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=75 -XX:+UseCMSInitiatingOccupancyOnly
minor gc 频率过高可以试着调整年轻代变大,
但是变大会出现的问题:可能出想大对象,在老年代内存担保,导致还是很老的对象进入老年代
导致老年代在增长
full gc比minor gc还多的原因有哪些?
1、元空间不够导致的多余full gc
2、显示调用System.gc()造成多余的full gc,这种一般线上尽量通过-XX:+DisableExplicitGC参数禁用,如果加上了这个JVM启动参数,那么代码中调用System.gc()没有任何效果
3、老年代空间分配担保机制
内存泄漏
JVM级缓存使用一个简单的Map,不断加入元素,导致map增大,在老年代占用,导致的full gc
最好使用 enCache框架, 带有LRU 算法的框架