专栏首页宜信技术实践记一次通过Memory Analyzer分析内存泄漏的解决过程

记一次通过Memory Analyzer分析内存泄漏的解决过程

状况描述:

最近项目新打的版本,过不了多长时间,项目就会挂掉。状况就是处于一种假死的状态。索引查询都很慢,几乎进行不了任何操作,慢慢卡死。 然后我们再发版时,只能基于之前打好的war包,替换或者增加class文件。

情况对比及分析:

由于之前代码做过一次大整顿,提交的代码比较多,所以通过回滚版本的方式解决,比较困难。一是因为整顿的成果不能白白抹杀;二是那么多文件,靠人工挨个对比查找,比较困难。

解决方案一:

之前, 一直对目前项目的打包方式心存质疑,所以这次发生问题时,我首先怀疑的对象是Jenkins和生产的Tomcat服务器。我通过堡垒机连接到生产时,发现通过Jenkins启动应用程序,会启动两个两个tomcat进程。

然后,这似乎更加坚定了我的看法,马上就找到了运维,但是经确认后,是没有问题的。一个是用root用户启动的,一个是用tomcat用户启动的。一个守护进程,一个应用进程。

解决方案二:

排除了服务器的问题,开始正面考虑程序的问题。 重新发项目有问题的版本,Dump下来的日志,然后迅速回滚观察。单台机器的dump日志有5个G:

通过Memory Analyzer分析,在Leak Supects Report 视图中,有如下分析结果:

上图所示,共有三类问题a、b、c;还有一些其他的,类型为d。

先来看第一个问题(后来发现,前几个问题都是同一个问题)

先点开Details看一下:

上图显示了一个很明显的有问题的线程:地址是0x7c8ff3df0 ,名称为pool-16-thread-1。 通过《Accumulated Objects in Dominator Tree》视图可以看出,在该线程中,存在一个大的List对象,List对象内存放了大量的mysql的jdbc对象。

我们想看看JDBC对象里面堆放了哪些数据。接下来我们打开《open dominator tree for entire heap》这个视图:

找到名为0x7c8ff3df0 pool-16-thread-1的线程。如图也能发现,这个线程占用了大量的空间未释放。一层层打开里面的存放的对象:

这里的数据,是我们的一张用户表的数据。所以这就可以得出结论:一个线程内,一个list内存放了大量从数据库中获取的用户对象! 想到这里,我们又去看了b、c的问题描述,也是同样的问题。估计是在不同时间点,通过gc已经回收了部分。

然后,我刚才看了a问题的details信息,接下来我们看下a的stacktrace 堆栈信息。

如上图,问题就很明显了,在Service的112行中,调用的findByCustomerID方法中,有扫描全表的操作。经过分析,找到对应的位置,对应的代码为:

customerID = StringUtils.isNotBlank(customerID)?customer.getCustomer().getCustomerID():null;

                        Customer oldCutsomer = customerService.findByCustomerID(customerID);

显而易见,流程走到这里时,customerID永远为空,那么customerService.findByCustomerID(customerID)方法,会执行扫描全表操作。由于该表数据量巨大,开发所认为的用户每次执行的索引查询,实际上都成了慢查询,而且需要返回全表数据。大量线程过来,占用大量数据库连接,导致数据库连接数不够;而每个线程处理时,需要大量时间,  导致项目处于一种假死的状态。

总结分析:

1、在工作中一定要规范代码管理,才能提升开发效率,降低企业遭受损失的风险;

2、通过这次实践发现,目前开发权限小,导致跨部门协同效率不是很高,接下来的开发中,立项之初就建立项目开发流程,从而提升开发效率;

3、解决问题的方法遇到瓶颈,尝试第二种方法,多角度多层次对问题进行突破。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Redis专题(3):锁的基本概念到Redis分布式锁实现

    近来,分布式的问题被广泛提及,比如分布式事务、分布式框架、ZooKeeper、SpringCloud等等。本文先回顾锁的概念,再介绍分布式锁,以及如何用Redi...

    宜信技术学院
  • SpringCloud微服务架构升级实践

    起源:微服务的概念源于 2014 年 3 月 Martin Fowler 所写的一篇文章“Microservices”。文中内容提到:微服务架构是一种架构模式,...

    宜信技术学院
  • 如何设计实时数据平台(设计篇)

    导读:本文将会分上下两篇对一个重要且常见的大数据基础设施平台展开讨论,即“实时数据平台”。

    宜信技术学院
  • 异步时代-java的协程路在何方

    很尴尬,但是事实是,很大一部分的程序员不知道协程是啥玩意,更大一部分的程序员,项目中没用到协程。

    生活创客
  • JVM故障分析及性能优化实战(II)——jstack生成的Thread Dump日志结构解析

    上一篇文章讲述了如何使用jstack生成日志文件,这篇文章首先对Thread Dump日志文件的结构进行分析。

    IT技术小咖
  • CAS机制是什么?

    因为多核CPU的存在,总是需要保障程序高性能的利用计算机的CPU资源,并要保障计算结果与预期的一致。因此常用的方式就是加锁方式。就是占用->占用结束->释放的...

    用户5602455
  • Java 经典问题

    switch语句后的控制表达式只能是short、char、int、long整数类型和枚举类型,不能是float,double和boolean类型。String类...

    好好学java
  • 【JVM调优(一)】----JAVA内存模型抽象结构

    线程之间的通信机制有两种:共享内存和消息传递。 Java线程之间的通信由Java内存模型(JMM)控制,JMM控制一个线程对共享变量的写入什么时候对另一个...

    令仔很忙
  • PHP到底能不能实现多线程?

    前些天帮同事查一个问题,第一次接触到了 PHP 的多线程,原以为 PHP 普遍都是单线程模型,并不适合多线程领域,花些时间翻了几个多线程的项目源码之后,发现 P...

    卡二条的技术圈子
  • 面试总结-Java高级篇

    java.util.Collections 是一个包装类。它包含有各种有关集合操作的静态多态方法。

    Java搬砖工人

扫码关注云+社区

领取腾讯云代金券