一.溢出现象
单台服务器刚发布时 java 进程占用3g,以一天5%左右的速度增长,一定时间过后进程占用接近90%,触发服务器报警,而此时 Old 区占用在 50%,未触发 CMS GC,而导致堆外内存溢出。
异常堆栈:
top 命令查看进程占用:
机器为 8核16G,JVM配置如下:
-Xms8g -Xmx8g -Xmn3g -Xss512k
-XX:MetaspaceSize=256m
-XX:MaxMetaspaceSize=512m
-XX:+UseConcMarkSweepGC
-XX:+DisableExplicitGC
-XX:-UseGCOverheadLimit
-XX:+UseCMSInitiatingOccupancyOnly
-XX:CMSInitiatingOccupancyFraction=70
-XX:+CMSParallelRemarkEnabled
-XX:+UseFastAccessorMethods
大数据是未来的发展方向,正在挑战我们的分析能力及对世界的认知方式,因此,我们与时俱进,迎接变化,并不断的成长!大数据学习群:957205962 一起讨论进步学习
二.排查过程&原理分析
1.初步分析
根据异常堆栈,可以看出是 hbase.write() 分配直接内存导致的堆外内存溢出。而直接内存分配空间不足时,会调用 System.gc(),由于 JVM 参数配置了 -XX:+DisableExplicitGC 禁用了 System.gc(),且 Old 区占用才50%,未达到 CMS GC 阈值,因此抛出堆外内存溢出。
粗略的堆外内存计算方式:
JVM 未设置直接内存大小参数 -XX:MaxDirectMemorySize, 则 CMS GC堆外内存为:Old 区 - 1个 Survivor 区, 即 8G - 314M = 7.8G。
2.压测主要接口
因为不能用线上机器做实验,且不能确定是否有其他因素导致溢出。于是在性能环境使用 Jmeter 压测应用主要接口,并观察堆外内存占用。
压测后发现堆外内存占用平稳,未出现溢出现象。
3.释放 HBase Client 资源
此时将目光放到异常堆栈上,并查看系统封装的 hbase client ,发现使用完 HTable 后未调用 close() 释放资源,于是加上 close() 代码,并上线观察。但仍然出现溢出现象。
4.压测特定功能
虽然不是 HBase Client 使用的问题,但还是有相同的堆栈&#x