记录一次OSSClient使用不当导致的OOM排查过程

news2024/11/22 18:19:51

首发:公众号《赵侠客》

前言

最近线上有个比较边缘的项目出现OOM了,还好这个项目只是做一些离线的任务处理,出现OOM对线上业务没有什么影响,这里记录一下排查的过程

Dump日志查看

项目配置的主要JVM参数设置如下:

-Xmx5120m -XX:+PreserveFramePointer -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/usr/local/update/heap_trace.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/local/update/dump.log 

最大堆内存给了5G,并配置了记录GC日志,OOM后的内存导出,我们先看一下OOM的导出内存快照,dump.log居然有5GB,第一判断肯定是内存泄漏了。

然后看了一下heap_trace.log的GC日志,最后几次GC花了0.02秒,并且没有释放多少内存,肯定是内存泄漏了

2023-09-18T09:58:28.259+0800: 234057.213: [GC (Allocation Failure) [PSYoungGen: 438400K->7648K(441344K)] 763838K->333358K(961024K), 0.0140907 secs] [Times: user=0.04 sys=0.00, real=0.02 secs]  
2023-09-18T10:01:33.925+0800: 234242.879: [GC (Allocation Failure) [PSYoungGen: 436704K->7344K(441856K)] 762414K->333326K(961536K), 0.0134861 secs] [Times: user=0.04 sys=0.00, real=0.01 secs]  
2023-09-18T10:04:16.426+0800: 234405.380: [GC (Allocation Failure) [PSYoungGen: 437424K->8832K(441856K)] 763406K->335022K(961536K), 0.0147276 secs] [Times: user=0.05 sys=0.00, real=0.01 secs]  
2023-09-18T10:06:30.923+0800: 234539.877: [GC (Allocation Failure) [PSYoungGen: 438912K->11520K(442368K)] 765102K->338158K(962048K), 0.0202829 secs] [Times: user=0.06 sys=0.00, real=0.02 secs]  
2023-09-18T10:08:27.655+0800: 234656.609: [GC (Allocation Failure) [PSYoungGen: 442112K->12272K(442880K)] 768750K->340510K(962560K), 0.0216111 secs] [Times: user=0.06 sys=0.00, real=0.02 secs]  
2023-09-18T10:11:37.773+0800: 234846.727: [GC (Allocation Failure) [PSYoungGen: 442864K->12000K(445440K)] 771102K->340918K(965120K), 0.0243473 secs] [Times: user=0.06 sys=0.00, real=0.02 secs]  
2023-09-18T10:14:56.925+0800: 235045.879: [GC (Allocation Failure) [PSYoungGen: 443616K->8192K(445952K)] 772534K->337110K(965632K), 0.0152287 secs] [Times: user=0.04 sys=0.00, real=0.01 secs]  
2023-09-18T10:17:49.358+0800: 235218.312: [GC (Allocation Failure) [PSYoungGen: 439808K->8432K(445952K)] 768726K->337790K(965632K), 0.0151303 secs] [Times: user=0.05 sys=0.00, real=0.02 secs]  
2023-09-18T10:20:51.356+0800: 235400.310: [GC (Allocation Failure) [PSYoungGen: 441072K->8976K(446464K)] 770430K->338470K(966144K), 0.0159285 secs] [Times: user=0.05 sys=0.00, real=0.02 secs]  
2023-09-18T10:24:05.395+0800: 235594.349: [GC (Allocation Failure) [PSYoungGen: 441616K->9504K(446464K)] 771110K->339358K(966144K), 0.0219962 secs] [Times: user=0.05 sys=0.00, real=0.02 secs]  
2023-09-18T10:26:48.374+0800: 235757.328: [GC (Allocation Failure) [PSYoungGen: 443168K->11680K(446976K)] 773022K->341950K(966656K), 0.0195554 secs] [Times: user=0.05 sys=0.00, real=0.02 secs]

使用Jprofiler分析Dump文件

使用JProFiler打开Dump文件可以看到HashMap$Node居然有1GB

我们选择Node,发现有3000多万个对象:

我们选择Merged incoming references ,然后一步步的展开Node对象的引用链,最后我们发现有个OSSClient的对象引用了Node

想到这个业务大量使用了阿里云OSS上传文件,于是找到使用OSSClient的代码,代理中上传文件每次new OSSClient(),但是就算是每次new 个局部变量,也不应该会导致内存泄漏啊?

于是我了一下DefaultServiceClient的源码,我们可以看到创建OSSClient时调用了createHttpClientConnectionManager

    public DefaultServiceClient(ClientConfiguration config) {
        super(config);
        this.connectionManager = createHttpClientConnectionManager();
        this.httpClient = createHttpClient(this.connectionManager);
        RequestConfig.Builder requestConfigBuilder = RequestConfig.custom();    
        

createHttpClientConnectionManager中使用了IdleConnectionReaper来管理当前连接:

    protected HttpClientConnectionManager createHttpClientConnectionManager() {
        SSLContext sslContext = null;
      if (config.isUseReaper()) {
            IdleConnectionReaper.setIdleConnectionTime(config.getIdleConnectionTime());
            IdleConnectionReaper.registerConnectionManager(connectionManager);
        }
        return connectionManager;
    }

IdleConnectionReaper.registerConnectionManager中我们可以看到使用了ArrayList来存所有的HTTP连接

public final class IdleConnectionReaper extends Thread {
    private static final int REAP_INTERVAL_MILLISECONDS = 5 * 1000;
    private static final ArrayList<HttpClientConnectionManager> connectionManagers = new ArrayList<HttpClientConnectionManager>();

    private static IdleConnectionReaper instance;

    private static long idleConnectionTime = 60 * 1000;

    private volatile boolean shuttingDown;

    private IdleConnectionReaper() {
        super("idle_connection_reaper");
        setDaemon(true);
    }

    public static synchronized boolean registerConnectionManager(HttpClientConnectionManager connectionManager) {
        if (instance == null) {
            instance = new IdleConnectionReaper();
            instance.start();
        }
        return connectionManagers.add(connectionManager);
    }

我们看到OSSClient提供了一个shutdown方法,new过的OSSClint如果不用了需要调用shutdown来释放连接,会从connectionManagers中移除对接的连接,好吧,确实是代码使用不当导致的OOM。

    @Override
    public void shutdown() {
        IdleConnectionReaper.removeConnectionManager(this.connectionManager);
        this.connectionManager.shutdown();
    }  
  public static synchronized boolean removeConnectionManager(HttpClientConnectionManager connectionManager) {
        boolean b = connectionManagers.remove(connectionManager);
        if (connectionManagers.isEmpty())
            shutdown();
        return b;
    }

我在阿里云官网也找到同样的问题:
image.png

解决方法:

  1. 将 OSSClient 实例定义为单例模式,避免在应用中多次实例化 OSSClient
  2. 使用 OSSClient.shutdown() 方法关闭 OSSClient 实例,释放资源
  3. 使用 try-finally 块,在 finally 中调用 OSSClient.shutdown() 方法
  4. 在应用中使用 OSSClient 的过程中,确保使用完成后关闭 OSSClient 实例

本地复现

我们本地启用项目使用Jprofiler连接我们的JVM

这个功能是对外提供了一个接口,于是我们写个for循环一直请求这个接口,然后观察内存变化,跑了6分钟可用内存就变成了0

服务端也报了OOM:

解决问题

使用工厂模式重写代码:

    public static final Map<String, OSSClient> map = new ConcurrentHashMap<>();
    public static OSSClient getClient(String endpoint, String accessKey, String accessSecret) {
        if (!map.containsKey(accessKey)) {
            OSSClient client = new OSSClient(endpoint, accessKey, accessSecret);
            map.put(accessKey, client);
        }
        return map.get(accessKey);
    }

替换原来的代码:

  OSSClient client = AliyunUtil.getClient(endpoint, getAccessKey(), getAccessSecret());

再次测试,发现每次GC都很好释放了内存,跑了6分钟,内存使用不超过200M,完美解决了问题

总结

本文介绍了使用Jprofiler排查一次线上由于使用阿里云OSSClient不当导致的OOM过程,主要还是写代码时没有注意OSSClient需要自己手动Shutdown导致的,还好不是出现在核心业务系统中,不然后果就比较麻烦了,以后使用别人提供的工具时一定要多看看官方是如何使用,多翻翻源码,避免再出现类似的问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1021049.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SAP入门到放弃系列之QM质量检验流程概述

目录 一、流程概述二、操作步骤概述2.1 主数据维护2.2 业务操作 一、流程概述 质量检验流程-Inspection Process Flow,通常由于预先设定的一些规则条件自动触发或者手工触发&#xff0c;例如库存地之间的调拨、生产完工入库检验、采购入库的检验、客户交货前检验等等。另外还有…

GMS地下水数值模拟丨GMS各模块、三维地质模型构建及与MODFLOW耦合、地下水流动数值模拟及报告编制、地下水溶质运移模型、反应性溶质运移等

目录 第一部分 地下水数值模拟理论模块 第二部分 地下水数值模拟数据收集、准备及预处理 第三部分 GMS各模块实践 第四部分 三维地质模型构建及与MODFLOW耦合 第五部分 地下水流动数值模拟及报告编制 第六部分 地下水溶质运移模型 第七部分 反应性溶质运移 更多应用 以…

OpenHarmony ArkTS工程目录结构(Stage模型)

一、应用工程结构 图片来源&#xff1a;OpenHarmony官网 AppScope > app.json5&#xff1a;应用的全局配置信息。 entry&#xff1a;OpenHarmony工程模块&#xff0c;编译构建生成一个HAP包。 src > main > ets&#xff1a;用于存放ArkTS源码。 src > main > …

昔日顶流VC宠儿,如今“流血”上市!

今年全球最大IPO安谋控股&#xff08;Arm Holdings&#xff09;成功上市后&#xff0c;美国的IPO市场正在被激活。美国最大的杂货配送平台Instacart近日更新了招股书&#xff0c;将IPO目标价从原来的26-28美元每股上调至28-30美元&#xff0c;对应公司估值约77亿美元-82.8亿美元…

SpringSecurity 核心组件

文章目录 SpringSecurity 结构组件&#xff1a;SecurityContextHolder组件&#xff1a;Authentication组件&#xff1a;UserDetailsService组件&#xff1a;GrantedAuthority组件总结 SpringSecurity 结构 在SpringSecurity中的jar分为4个&#xff0c;作用分别为 jar作用spri…

idea配置tomcat项目,运行起来却无法访问项目

好长时间都没碰使用tomcat部署的老项目了 最近碰到一个tomcat老项目&#xff0c;都忘记怎么用idea配置了 按记忆配置好之后&#xff0c;启动tomcat&#xff0c;却怎么也访问不了项目 最后才发现根本没有启动编译后的项目代码 只需要右键项目&#xff0c;选择Open Module Se…

如何通过百度SEO优化提升网站排名(掌握基础概念,实现有效优化)

随着互联网的发展&#xff0c;搜索引擎优化&#xff08;SEO&#xff09;成为了网站优化中不可或缺的一部分。在中国&#xff0c;百度搜索引擎占据着主导地位&#xff0c;因此掌握百度SEO概念和优化技巧对网站的排名和曝光非常重要。 百度SEO排名的6个有效方法&#xff1a; 首…

福建企业可以申请泛域名https证书吗

https域名https证书中有一种比较特殊的https证书&#xff0c;可以用一张https证书保护主域名以及主域名下所有子域名&#xff0c;这种证书通常被称为通配符https证书或泛域名https证书。那么企业可以申请泛域名https证书吗?今天就随SSL盾小编了解泛域名https证书。 1.泛域名h…

共享门店模式:让你的连锁门店变成金鸡母

共享门店模式是一种创新的经营方式&#xff0c;它可以让门店的资源和收益与其他人共享&#xff0c;实现互利共赢。共享门店模式有两种主要形式&#xff1a;投资型和消费型。投资型共享门店模式需要股东投入一定的资金&#xff0c;用于锁客和获取分红收益。消费型共享门店模式则…

【免费内网穿透】cpolar从0开始使用

cpolar从0开始使用 具体步骤cpolar下载注册安装 安装启动创建或修改启动 公网远程访问内网web站点初步完成 最近学习到的新东西。 原理类似于使用cpolar的服务器进行跳转 具体步骤 下载CPOLAR 在您的机器上下载并运行cpolar客户端&#xff0c;并为其提供一个本地的网络服务的…

如何合并pdf?三种合并方法教会你

如何合并pdf&#xff1f;合并PDF文件可以将多个PDF文档合并为一个文件&#xff0c;提高文件管理的效率和便利性。无论是为了整理和归档文件&#xff0c;还是为了方便共享和传输文件&#xff0c;合并PDF都是非常实用的操作。通过合并PDF&#xff0c;可以将相关的文件整合在一起&…

项目管理:管理成果是控制还是天意?项目经理的责任是什么?

有人坚信管理具有决定性的作用&#xff0c;主张管理者需对组织的成功或失败负全责。 另一些人则认为&#xff0c;管理者对管理成果的影响其实相当有限&#xff0c;因为存在许多他们无法控制的因素。 组织的成功或失败往往更多地归因于这些无法控制的因素&#xff0c;而非管理者…

浏览器代理解决方案

当谈到网络浏览器&#xff0c; 浏览器 无疑是最受欢迎和广泛使用的选项之一。然而&#xff0c;你可能已经注意到&#xff0c; 浏览器并不原生支持 SOCKS5 代理协议。不过&#xff0c;别担心&#xff01;在本文中&#xff0c;我将与你分享一些解决方案&#xff0c;让你能够在 浏…

黑马JVM总结(十三)

&#xff08;1&#xff09;软引用_引用队列 上面我们们使用软引用我们发现在内存不足时&#xff0c;会把软引用对应的Byte数组对象&#xff0c;进行一个释放&#xff0c;但是我们发现遍历lIst集合的时候一些软引用的对象已经是null了&#xff0c;这些没必要在把它们保存到List…

哨兵模式(sentinel)

为什么需要哨兵模式 redis的主从复制模式能够缓解“读压力”&#xff0c;但是存在两个明显问题。 主节点发生故障&#xff0c;进行主节点切换的过程比较复杂&#xff0c;需要人工参与&#xff0c;导致故障恢复时间无法保障主节点通过主从复制模式将读压力分散出去&#xff0c…

【算法】算法设计与分析 课程笔记 第一章 概述

第一章 算法概述 算法的性质 算法的四个性质&#xff1a;输入、输出、确定性和有穷性。 算法的时间复杂度 1. 常见的时间复杂度 常数阶 O(1) 对数阶 O(log n) 线性阶 O(n) 线性对数阶 O(nlog n) 平方阶 O(n^2) 立方阶 O(n^3) k 次方阶 O(n^k) 指数阶 O(2^n) 注&…

Prompt 策略:代码库 AI 助手的语义化搜索设计

在过去的一周里&#xff0c;为了更好的构建 AI Agent 框架 Chocolate Factory&#xff08;以下简称 CF&#xff09;&#xff0c;我们加入了一个新的应用&#xff1a;代码库 AI 助手。 在设计时&#xff0c;为了更好的在框架底层提供这种能力&#xff0c;我们参阅了 Bloop 应用、…

科研小工具|慢性阻塞性肺疾病全球创议

简介 慢性阻塞性肺疾病全球创议&#xff08;the Global Initiative for Chornic Obstructive Lung Disease&#xff0c;GOLD&#xff09;是慢性阻塞性肺疾病&#xff08;COPD&#xff09;诊断、治疗与预防在全球范围内的标准。颁布GOLD的目的在于&#xff0c;增加医疗卫生工作…

pdd24版滑块

最近pdd改版了&#xff0c;在原来的基础之上加了一个content字段&#xff0c;然后pdd滑块分为两个大类。 一个是22类型的&#xff0c;在之前的文章里面有介绍&#xff0c;感兴趣也可以去看看。 详情的滑块跟普通的版本不同&#xff0c;但是有的算法也沿用了之前22版的东西&a…

【Seata】05 - Seata Saga 模式简单整理、Docker 部署 Nacos 单机(基于 Jpom)相关配置

文章目录 前言参考目录Saga 模式知识点简单整理1、适用场景、优缺点2、Saga 模式的使用3、可能出现的问题以及解决方法 Docker 部署 Nacos 单机&#xff08;基于 Jpom&#xff09;步骤 1&#xff1a;拉取镜像步骤 2&#xff1a;构建容器步骤 3&#xff1a;Nacos 设置 Seata 配置…