根据堆栈日志定位内存泄漏

【问题描述】:服务后端是3节点集群,凌晨出现2节点磁盘打满告警并致使业务中断,定位发现是jvm堆栈日志hprof,该文件比较大(大概10G+)。恢复线上业务后,恰好另外一节点磁盘没有满,并打出堆栈日志,能够用来定位这次故障缘由。linux

工具:MemoryAnalyzer-1.8.1.20180910-win32.win32.x86_64后端

tomcat bin/setenv.sh配置堆栈日志:tomcat

export CATALINA_OPTS="$CATALINA_OPTS -XX:+HeapDumpOnOutOfMemoryError"
export CATALINA_OPTS="$CATALINA_OPTS -XX:HeapDumpPath=/opt/admin/logs/CloudNetmonitor-Computer"安全

【定位过程】:服务器

第一步 从线上导出堆栈日志到本地分析网络

   因为公司安全策略,线上与本地网络隔离,须要堡垒机传送文件而且限制大小,在linux服务器上须要拆分日志文件:jvm

   拆包: tar czf - sourcefile | split -b 90m - dest_split.工具

   合并:cat dest_split.* >> dest.tar.gz线程

   解包:tar zxvf dest.tar.gz日志

第二步 启动MAT工具

   启动前配置MemoryAnalyzer文件,调大内存 -Xmx12g

   MAT工具 File- Open Head Dump 导入hprof文件,大文件可能持续一段时间,导入后

  

第三步 分析内存泄漏

首先根据 饼状图能够直观的发现,有内存泄漏9.7G,点击 leak suspecks 能够查看可疑泄漏位置,点击查看详细,可发现是RedisListenerPool这个类中定义的 固定线程池引用变量堆内存过大。

 

MAT工具提供的分析仍是比较全面,查看“Accumulated Objects in Dominator Tree”,发现是线程池队列长度打满,并且该队列是个链表阻塞队列,转到对应代码位置

 

问题代码位置:

private ExecutorService fixedThreadPool = Executors.newFixedThreadPool(10);

查看固定线程池源码:

    找到问题了,这里默认定义的是不指定容量大小的阻塞队列,意味着是无限大小。做为开发者,咱们须要注意的是,若是构造一个LinkedBlockingQueue对象,而没有指定其容量大小,LinkedBlockingQueue会默认一个相似无限大小的容量(Integer.MAX_VALUE),这样的话,若是生产者的速度一旦大于消费者的速度,也许尚未等到队列满阻塞产生,系统内存就有可能已被消耗殆尽了。

相关文章
相关标签/搜索