龙之队|一次线上JVM内存溢出分析,GC分析、MAT、gcviewer

maxHttpHeaderSize带来的问题
前因我们的服务是部署在docker容器中 , 使用SpringBoot框架搭建的微服务 , jdk版本是open jdk 1.8_u201版 , 内存分配了4G , 共部署了4个微服务 , 使用gateway作为网关负载均衡 。 有一天运营团队通知我 , 我们的服务不能访问 , 访问的页面都是没有数据的;我随即查看我们的系统运行状况 , 我是通过docker exec -it <容器ID> jstat -gcutil1000来查看的;发现系统的年轻代占用50% , 老年代占用97% , 元空间占用93% , 查看GC次数发现没有触发FullGC , 只是触发了YGC 68次 。
这下让我产生疑问 , 为什么内存几乎被占满了 , jvm还不进行FullGC呢?于是我通过命令docker exec -it <容器ID> jmap -dump:file=来生成dump快照文件 , 还有获取项目中的gc日志 。 而且通过MAT分析dump、使用gcviewer分析GC日志 。
MAT分析工具gcviewer
先来看看GC日志情况
java -jar ./gcviewer.jar service_gc.log
龙之队|一次线上JVM内存溢出分析,GC分析、MAT、gcviewer这里可以看到总的GC暂停次数和时间 , 和FullGC暂停次数和时间
龙之队|一次线上JVM内存溢出分析,GC分析、MAT、gcviewer
龙之队|一次线上JVM内存溢出分析,GC分析、MAT、gcviewer项目刚刚启动时 , GC情况 , jvm堆内存逐步变大 , 黄色代表年轻代 , 紫色代表老年代 。
龙之队|一次线上JVM内存溢出分析,GC分析、MAT、gcviewer到最后的阶段
我们再来看看MAT分析情况是怎样:
龙之队|一次线上JVM内存溢出分析,GC分析、MAT、gcviewer出现两个可能发生内存溢出的问题

  1. byte[]占用堆内存比例约为46.24%
  2. 有61个实例Http11OutputBuffer被系统加载 , 总共耗费内存46.16%

龙之队|一次线上JVM内存溢出分析,GC分析、MAT、gcviewer这里的指向的问题的线程是org.apache.tomcat.util.threads.TaskThread
龙之队|一次线上JVM内存溢出分析,GC分析、MAT、gcviewer继续往下看 , 发现跟我们项目有点接近的东西tk.mybatis.mapper.mapperhelper.EntityHelper , 这个是实体类工具类 - 处理实体和数据库表以及字段关键的一个类 。 我们使用了这个插件 , 相信大家用过mybatis都会知道MyBatisPlus , 其实tk.mapper做的功能也是和MyBatisPlus差不多 。
那么这里为啥会装那么多的tk.mapper对象呢 , 主要来源是查数据库后转换实体类而创建的 , 我们再看看他的GC Roots最近节点
龙之队|一次线上JVM内存溢出分析,GC分析、MAT、gcviewer
龙之队|一次线上JVM内存溢出分析,GC分析、MAT、gcviewer发现都是在org.apache.tomcat.util.threads.TaskThread类引用 , 我们打开这个类看看源码 。


推荐阅读