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


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

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

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

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

    【定位过程】:

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

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

       拆包: 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),这样的话,如果生产者的速度一旦大于消费者的速度,也许还没有等到队列满阻塞产生,系统内存就有可能已被消耗殆尽了。

      

  • 相关阅读:
    为什么要用where 1=1?
    idea中.ignore忽略提交文件到Git的使用
    IDEA开发工具使用 git 创建项目、拉取分支、合并分支
    Linux常用命令及Linux系统根目录下各个目录的作用
    Xshell和Xftp的安装与使用教程
    Moco使用简单指导
    这样写会有什么问题呢?
    grunt学习笔记
    基于nginx的WebSocket反向代理
    maven依赖查找方法
  • 原文地址:https://www.cnblogs.com/albertarmstrong/p/10153976.html
Copyright © 2020-2023  润新知