前言

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

基础故障处理工具

都是利用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在这里应该是防止指令的重排序。
在这里插入图片描述

结果

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

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐