由JDK bug引发的线上OOM

由JDK bug引发的线上OOM

最近生产环境的一个应用忽然发生了OOM,还好是业务低峰期,没有导致什么严重问题,下面记录下本次排查的过程;

故障临时处理

在某天下午,正在愉快的写代码时,忽然看到业务反馈支付服务不能用的消息,因为最近没有发布,所以感觉不会是什么大事,十有八九是网络波动啥的,毕竟之前遇到过好多次,那剩下的就是找证据了,先看看日志,有没有报错(暂时还未接告警,所以要人肉看),结果不看不要紧,一看吓一跳,日志密密麻麻全都是OOM报错

微信公众号:代码深度研究院

幸好作者这百年Java开发经验不是白给的,反手就是一个重启服务,虽然看起来只是一个简单的重启,但是操作起来可并不简单,里边的道道还是很多的,重启的时候要注意留一台作为现场保护起来,同时给这台保留现场的实例的流量摘除掉,然后给其他实例重启起来,这样用户就能正常使用了;

本来以为事情到这里就结束了,但是就当我准备继续下一步的时候,我发现重启的早的那台机器内存已经又直线上升上来了;

微信公众号:代码深度研究院

不过这也难不倒我,既然重启后服务内存又开始飙升,说明肯定是定时任务、批处理之类的触发了,查看了下日志,果然是有大批的定时任务在执行,将定时任务暂停后发现就好了,下面开始对现场进行分析;

现场处理

登录到我们保留的现场机器上,使用下面的命令执行堆dump,方便我们后续分析:

# 安装gdb,如果机器上有就无需安装
yum install -y gdb# 设置不限制core dump大小
ulimit -c unlimited# 生成core dump,文件名叫core,也可以自己起名,100是目标Java进程pid,这个需要根据实际的来,命令执行完毕后会生成一个core.100的core dump
gcore 100 -o core

有的同学可能看到这里就开始迷糊了,Java堆dump不是用jmap命令吗,上边的命令跟jmap也没什么关系呀,我们这里之所以用gcore而不是jmap来dump,主要是因为在OOM时,通常JVM已经无法正常使用jmap来dump了(针对本次排查就是这种情况),如果你一定要使用jmap来操作,那么他会报错,无法进行堆dump,同时会在错误信息中告诉我们可以尝试使用jmap -F参数来进行堆dump,但是加上这个参数后,你会发现噩梦开始了,因为此时虽然能正常进行dump,但是速度可以说是惨不忍睹,4G的堆dump时间要按小时算,本质上是因为当我们使用jmap -F来进行堆dump的时候实际上底层使用了ptrace来dump(使用ptrace读取目标进程内存然后写出到文件),由于ptrace一次最多只能读取4字节(32位机器),所以导致他的速度也极其的慢; 而gcore生成速度相对于正常jmap来说也是比较快的,对于jmap -F就更快了; 所以,基于以上几点,我们选择了使用gcore来进行堆dump;

当我们使用gcoredump完后,因为最终还是需要使用Java系的工具进行内存分析,所以还是要将core dump转换为Java的堆dump,此时我们就可以执行以下命令来转换了:

注意,core dump完成后就可以先重启服务了,重启完服务再进行下面的步骤;

# 生成堆dump
jmap -dump:format=b,file=heap.hprof `which java` core.100

堆dump生成完毕后,将其下载下来,然后导入eclipse Memory Analyzer(MAT)开始分析,发现大量org.bouncycastle.jce.provider.BouncyCastleProvider实例被javax.crypto.JceSecurity类的verificationResults这个静态字段持有,下面就可以开始源码分析了;

具体怎么分析出是这个地方内存泄漏这里不做单独说明了,可以自行查询官方使用文档,后续也会考虑单独出一期分析方法的文章;

问题分析

查看javax.crypto.JceSecurity的源码,发现verificationResults是一个map,同时只在getVerificationResult这个方法中被放入了数据,源码如下:

微信公众号:代码深度研究院

经过结合我们的业务代码分析,发现是我们调用了javax.crypto.Cipher.getInstance(java.lang.String, java.security.Provider)这个方法,这个方法调用了javax.crypto.JceSecurity.getVerificationResult方法;getVerificationResult这个方法比较简单,就是对我们提供的java.security.Provider所在的jar进行签名校验,校验完毕后将我们提供的Provider作为key、校验结果作为value放入verificationResults这个map缓存,下次就不用校验了,但是这里有个问题,就是这个缓存没有任何清理机制,也就意味着我们如果频繁调用javax.crypto.Cipher.getInstance(java.lang.String, java.security.Provider)来获取AES实例的话,就是可能会导致内存泄漏的,经过我们验证,也确实是这样,可以使用以下代码复现:

注意指定jvm参数: -Xmx128m

import java.security.NoSuchAlgorithmException;import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;import org.bouncycastle.jce.provider.BouncyCastleProvider;/*** @author JoeKerouac* @date 2023-08-24 12:50*/
public class Test {public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchPaddingException {for (int i = 0; i < 500; i++) {Cipher c = Cipher.getInstance("AES", new BouncyCastleProvider());}}}

问题解决

既然问题定位到了,那解决起来就比较简单了,我们可以把Provider实例全局共享,或者使用Provider的名字来获取AES实例,这样不去反复创建Provider而是使用同一个Provider,在JceSecurity中自然也不会内存泄漏,代码如下:

至于作者为什么不使用单例?那是因为AES并不是线程安全的,无法全局共享,当然,可以使用单例然后自行控制并发,或者使用对象池技术、ThreadLocal等来解决;

import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.Security;import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;import org.bouncycastle.jce.provider.BouncyCastleProvider;/*** @author JoeKerouac* @date 2023-08-24 12:50*/
public class Test {private static BouncyCastleProvider provider = new BouncyCastleProvider();public static void main(String[] args)throws NoSuchAlgorithmException, NoSuchPaddingException, NoSuchProviderException {// 使用全局共享的providerCipher cipher = plan1();// 使用provider的名字获取AES实例,其实本质上也是全局共享了provider// 注意,如果要使用provider的名字获取AES实例,要先注册Security.addProvider(new BouncyCastleProvider());cipher = plan2();}public static Cipher plan1() throws NoSuchAlgorithmException, NoSuchPaddingException {return Cipher.getInstance("AES", provider);}public static Cipher plan2() throws NoSuchAlgorithmException, NoSuchPaddingException, NoSuchProviderException {return Cipher.getInstance("AES", "BC");}}

问题溯源

这应该是一个比较容易发现的问题,既然这样,那有没有人提出这个问题呢,想到这里,作者打开了Google,经过一番搜索后(其实很容易就能搜到,只需要搜索关键字javax.crypto.JceSecurity#getVerificationResult即可),发现确实有人给jdk提了这个bug,而且也给出了解决方案,代码已经合并到了master,不过截至发文时,在作者使用的eclipse jdk(Temurin)中,jdk8jdk17这两个版本的最新发布中(2023-07-25发布)仍然存在该问题,并未修复,所以如果遇到该问题,还是需要使用上边的解决方案来处理;

官方bug记录:https://bugs.openjdk.org/browse/JDK-8168469

至此,我们的问题已经解决了,通过本篇文章,你应该大概知道了线上发生OOM时的处理流程了,以后碰到类似问题可以按照本流程来直接套用,至少大多数场景下都是可以的;

联系我

  • 作者微信:JoeKerouac
  • 微信公众号(文章会第一时间更新到公众号,如果搜不出来可能是改名字了,加微信即可=_=|):代码深度研究院
  • GitHub:https://github.com/JoeKerouac

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

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

相关文章

Ubuntu中删除LibreOffice方法

目录 删除LibreOffice套件 删除所有与LibreOffice相关的软件包 删除与LibreOffice相关的配置文件 删除LibreOffice套件 1、打开终端。您可以使用快捷键Ctrl Alt T来打开终端。 2、输入以下命令以卸载LibreOffice套件&#xff1a; sudo apt-get remove libreoffice* 删…

美容行业如何快速搭建自己的预约小程序?

现在&#xff0c;搭建一个专属于美容行业的预约小程序不再是只有程序员才能做到的事情了。有了一些小程序制作平台的存在&#xff0c;任何人都可以轻松地制作出自己的小程序。下面&#xff0c;我将揭秘一个快速搭建专属美容行业预约小程序的秘诀。 首先&#xff0c;登录小程序制…

数学建模(五)非线性规划

课程推荐&#xff1a; 13 非线性规划算法在数学建模中的应用与编程实现_哔哩哔哩_bilibili 一、非线性规划模型 如果目标函数或约束条件中包含非线性函数&#xff0c;就称这种规划问题为非线性规划问题。一般说来&#xff0c;解非线性规划要比解线性规划问题困难得多。而且&am…

2023年国赛数学建模思路 - 案例:退火算法

文章目录 1 退火算法原理1.1 物理背景1.2 背后的数学模型 2 退火算法实现2.1 算法流程2.2算法实现 建模资料 ## 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 退火算法原理 1.1 物理背景 在热力学上&a…

iOS 17 及 Xcode 15.0 Beta7 问题记录

1、iOS 17 真机调试问题 iOS 17之后&#xff0c;真机调试Beta版本必须使用Beta版本的Xcode来调试&#xff0c;用以前复制DeviceSupport 方式无法调试&#xff0c;新的Beta版本Xcode中&#xff0c;已经不包含 iOS 17目录。如下图&#xff1a; 解决方案&#xff1a; 1&#x…

多数元素00

题目链接 多数元素 题目描述 注意点 给定的数组总是存在多数元素多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素 解答思路 初始想到使用map存每个元素和元素出现的次数&#xff0c;但是时间和空间都不理想因为本题给定的数组总是存在多数元素&#xff0c;使用投票算…

GitLab-CI 指南

GitLab CI 指南 前置工作 部署GitLab 部署GitLab-Runner 注册Runner到GitLab docker exec -it gitlab-runner bash # 进入容器 gitlab-runner register #调用register命令开始注册 # 在Gitlab Setting中找到Runners,如下图所示Enter the GitLab instance URL (for example, …

高品质音乐下载命令行工具Musicn

又到了小苏同学的生日&#x1f382;&#xff0c;宝贝&#xff0c;生日快乐&#xff01;祝永远健康、快乐、心想事成&#xff01; 什么是 Musicn &#xff1f; Musicn 是一个可播放及下载高品质&#x1f3b5;音乐&#x1f3b5;的命令行工具。支持咪咕、酷我、酷狗和网易云的服务…

《中国区块链发展报告(2023)》发布 和数集团推动区块链发展

北京区块链技术应用协会与社会科学文献出版社日前在京共同发布《区块链蓝皮书&#xff1a;中国区块链发展报告&#xff08;2023&#xff09;》。蓝皮书归纳梳理了2022年区块链产业发展现状及趋势&#xff0c;并结合行业热点Web3.0、AIGC&#xff0c;探讨我国区块链发展的热点话…

变动的Python爬虫实现

在电商时代&#xff0c;了解商品价格的变动对于购物者和卖家来说都非常重要。本文将分享一种基于Python的实时监控电商平台商品价格变动的爬虫实现方法。通过本文的解决方案和代码示例&#xff0c;您将能够轻松监控商品价格&#xff0c;并及时做出决策。 一、了解需求和目标 在…

让你对es有一个初步的了解

首先es在海量数据的搜索能力非常好&#xff0c;es你可以把他看成一个搜索引擎数据库&#xff0c;他是个非关系型数据库。他的语法有很大的不同&#xff0c;好像都是json风格的。还有一点需要说的就是es 的数据是存在硬盘上的&#xff0c; 我们先来看一下mysql和es的区别吧。一…

vue中使用echarts三维的项目

需要安装 echarts 同时引入 echarts-gl 我安装的版本&#xff1a; "echarts": "^5.3.2", "echarts-gl": "^2.0.9", 效果 &#xff1a; 安装后main.js引入 import Vue from "vue"; import * as echarts from "echart…

实验八 网卡驱动移植

【实验目的】 掌握 Linux 内核配置的基本方法&#xff0c;完成对网卡驱动、NFS 等相关功能的配置 【实验环境】 ubuntu 14.04 发行版FS4412 实验平台交叉编译工具&#xff1a;arm-none-linux-gnueabi- 【注意事项】 实验步骤中以“$”开头的命令表示在 ubuntu 环境下执行&…

ChatGPT、Google Bard、Claude2、新BING哪一款人工智能聊天机器人适合自己

人工智能聊天机器人正在提高数无数专业人士的工作效率。下面我们就来看看目前最流行的几款强大的人工智能工具&#xff0c;以及它们具体如何帮助到你。 今年7月AI圈最大的动静之一便是AI初创公司Anthropic发布了其AI聊天机器人Claude最新版本——Claude2。该聊天机器人对标Open…

大数据课程K6——Spark的Shuffle详解

文章作者邮箱:yugongshiye@sina.cn 地址:广东惠州 ▲ 本章节目的 ⚪ 了解Spark的定义&&特点&&目的&&优缺点; ⚪ 掌握Spark的相关参数配置; ⚪ 掌握Hadoop的插件配置; 一、Spark Shuffle详解 1. 概述 Shuffle,就是洗牌。之所以…

力扣 337. 打家劫舍 III

题目来源&#xff1a;https://leetcode.cn/problems/house-robber-iii/description/ C题解1&#xff08;来源代码随想录&#xff09;&#xff1a;本题一定是要后序遍历&#xff0c;因为通过递归函数的返回值来做下一步计算。本题关键是要讨论当前节点抢还是不抢。如果抢了当前节…

关于数组和指针的笔试题解析(详解)

文章目录 说明&#x1f6a9;数组笔试题&#x1f4bb;一维数组&#x1f4c4;练习&#xff1a;&#x1f4a1;解析 &#x1f4bb;字符数组&#x1f4c4;练习1&#xff1a;&#x1f4a1;解析&#x1f4c4;练习2&#xff1a;&#x1f4a1;解析&#x1f4c4;练习3&#xff1a;&#x…

诚迈科技子公司智达诚远与Unity中国达成合作,打造智能座舱新时代

2023 年 8 月 23 日&#xff0c;全球领先的实时 3D 引擎 Unity 在华合资公司 Unity 中国举办发布会&#xff0c;正式对外发布 Unity 引擎中国版——团结引擎&#xff0c;并带来专为次世代汽车智能座舱打造的团结引擎车机版。发布会上&#xff0c;诚迈科技副总裁、诚迈科技子公司…

Wireshark数据抓包分析之UDP协议

一、实验目的&#xff1a; 通过使用wireshark对UDP数据包的抓取分析UDP协议的内容 二、预备知识&#xff1a; UDP协议的概念&#xff1a;UDP使用底层的互联网协议来传送报文&#xff0c;同IP一样提供不可靠的无连接传输服务。它也不提供报文到达确认、排序及流量控制等功能。 …

VScode中写Verilog时,iverilog语法自动纠错功能不起作用

VScode中编写Verilog时&#xff0c;iverilog语法自动纠错功能不起作用 问题&#xff1a;按照教程搭建vscode下Verilog编译环境&#xff0c;发现语法纠错功能一直无效&#xff0c;检查了扩展Verilog-HDL/SystemVerilog/Bluespec SystemVerilog的配置也没有任何问题。 错误原因&a…