JVM内存溢出排查--存在大量线程未回收

前言

一个单独调用第三方系统接口的小项目运行一段时间之后就出现了内存溢出,在此记录一下。

基础故障处理工具

都是利用jdk自带的工具

jps 虚拟机进程状况工具

可以列出正在运行的虚拟机进程 主要是用来查询pid的
在这里插入图片描述

jmap 虚拟机进程状况工具

这个功能比较强大

  1. jmap -heap pid 可以分析各代的分配内存 以及占用内存情况等
  2. jmap -histo pid 可以列举出堆中对象信息 实例数量、占用大小
  3. jmap -dump:format=b,file=文件名 pid 可以转成dump文件 利于后续的分析

jinfo Java配置信息工具

jinfo -flags pid 查看jvm参数
在这里插入图片描述

VisualVM:多合-故障处理工具

可视化的工具 jdk自带的就在bin目录下
在这里插入图片描述

排查流程

以下是模拟正式环境的本地排查过程,由于该项目是用来第三方提供的SDK调用他们的接口 我们就运行项目之后模拟调用多次看看情况

VisualVM查看项目运行状态

左侧本地选择项目就能查看cpu使用率、堆内存占用率、类数量、线程数量,还可以看各代的内存占用情况。
很显然我们一看就发现不对劲,线程活动数量很大和我们的调用次数基本相同。
在这里插入图片描述
在这里插入图片描述

通过jmap获取dump文件分析

通过jps 查询到pid 之后通过jmap -dump命令获取堆转储快照 然后通过VisualVM工具分析
发现有个对象和线程数大致相同并且占用率也挺高 ,开始查看代码
在这里插入图片描述

检查代码

追踪到代码 每次调用都创建了这个 init() 方法里面有创建线程

public static ExecutableClient initMethod() {
        ExecutableClient executableClient = ExecutableClient.getInstance();
        executableClient.setAccessKey(appKey);
        executableClient.setSecretKey(appSecret);
        executableClient.setDomainName(appUrl);
        executableClient.setProtocal("https");
        executableClient.init();
        return executableClient;
    }

在这里插入图片描述
在这里插入图片描述

单例模式

后面查看了第三方提供的文档 确实是需要单例的,开发的同事一开始没看到。
通过双重检查锁+volatile关键字实现单例。
提一下volatile在这里应该是防止指令的重排序。
在这里插入图片描述

结果

改完之后就正常了。
在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值