1.由于设置了值SoftRefLRUPolicyMSPerMB=0导致频繁触发full gc
jvm在反射过程中动态生成的类的class对象,他们都是SoftReference软引用的
软引用(SoftReference)在jvm内存不足的情况下会被回收
然后这个SoftRefLRUPolicyMSPerMB设置为0的情况下,会造成反射创建出来的软引用过期时间很短在ygc的时候会被回收掉,促使jvm不断的在创建反射所需的对象导到元数据频繁gc,元数据区的gc会触发full gc,从而导致了频繁的full gc
软引用可以被回收的条件:
clock-timestamp > freespace*SoftRefLRUPolicyMSPerMB
clock-timestamp 代表了一个软引用对象有多久没有被访问过
freespace代表jvm中空闲内存空间单位是MB
SoftRefLRUPolicyMSPerMB代表每一MB空闲内存空间可以允许SoftReference对象存活多久
剩余空间越大软引用对象存活时间越久
2.由于程序中有System.gc()的调用主动触发了full gc
建议在启动模板中添加-XX:+DisableExplicitGC使其失效,如果是那种NIO使用的比较多的情况下不能添加这个参数因为NIO那边会有需要触发System.gc(),尽量在代码中清除system.gc()这类
3.需要关注jvm的一些指标
1)E区的对象增长速率有多快
2)ygc频率有多高
3)一次ygc耗时多少
4)ygc过后存活对象是多少
5)老年代对象增长速率多高
6)fgc频率多高 几十分钟一次或者几小时一次都算比较正常
7)一次fgc耗时多少
4.线上系统监控和优化
通过工具Zabbix,Open-Falcon工具,频繁fgc报警机制
没有条件的情况下使用jstat写入到固定文件中去,定时查看其情况
5.fgc的几种表现和原因排查
现象:
1)机器cpu负载过高
2)频繁fgc报警
3)系统无法处理请求或者处理慢
原因排查:
1)系统承载高并发请求,处理数据量过大,导致ygc频繁,每次ygc之后存活对象太多,内存分配不合理,S区过小,导致内存泄漏频繁进入老年代,从而触发fgc
2)系统一次性加载过多数据进内存,导致频繁有大对象进入老年代,频繁fgc
3)系统内存泄漏,莫名其妙创建大量对象,一直占用老年代
4)永久代因为加载类过多触发fgc 有可能是谁设置了SoftRefLRUPolicyMSPerMB=0 引发了反射对象频繁被回收 导致不断创建软引用对象
5)误调用system.gc()触发fgc 采用-XX:+DisableExplicitGC使其失效即可但是如果是NIO文件系统那种的话由于这种考虑到临时对象比较多所以设计者会主动去调用system.gc(),所以不能禁用
先使用jstat查看 如果是第一种直接调整内存即可
如果是第二第三种那么就需要先dump出来内存快照(
命令 29513为进程号
jmap -dump:live,format=b,file=dump29513.hprof 29513
),然后采用MAT工具(
https://www.eclipse.org/mat/downloads.php
)进行分析揪出大对象
如果jstat发现内存使用并不多 那么就是第四第五种相应排查即可