前言
一个单独调用第三方系统接口的小项目运行一段时间之后就出现了内存溢出,在此记录一下。
基础故障处理工具
都是利用jdk自带的工具
jps 虚拟机进程状况工具
可以列出正在运行的虚拟机进程 主要是用来查询pid的
jmap 虚拟机进程状况工具
这个功能比较强大
- jmap -heap pid 可以分析各代的分配内存 以及占用内存情况等
- jmap -histo pid 可以列举出堆中对象信息 实例数量、占用大小
- 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在这里应该是防止指令的重排序。
结果
改完之后就正常了。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/15302.html