内存问题(三)——生成内存问题案例

一、系统非堆内存溢出问题排查

以下例子出自其他人案例,拿过来是为了学习排查问题思路,与解决思路。

1.1 现象描述

运单系统每隔一段时间,内存使用和CPU报警超出阈值85%,通过监控平台可以看到非堆内存持 续增加不回收
。导致频繁FullGC,引起CPU100%

1.2 操作系统监控图

在这里插入图片描述

1.3 JVM内存监控

在这里插入图片描述

  从监控上看非堆内存永久代(JDK8 HotSpot JVM将移除永久区,使用本地内存来存储类元数据信息并称之为:元空间(Metaspace))一直增加且无法回收。这部分内存主要用于存储类的信息、方法数据、方法代码等,正常情况下元空间不会占用很大内存,所以对于动态生成类的情况 比较容易出现永久代的内存溢出。开始怀疑应该是使用反射、代理等技术生成了大量的类加载到元 空间无法回收。

1.4 问题排查

1.4.1 使用jstat 查看内存及GC情况

在这里插入图片描述

各列含义: jstat (oracle.com)

  • S0C:第一个幸存区的大小
  • S1C:第二个幸存区的大小
  • S0U:第一个幸存区的使用大小
  • S1U:第二个幸存区的使用大小
  • EC:伊甸园区的大小
  • EU:伊甸园区的使用大小
  • OC:老年代大小
  • OU:老年代使用大小
  • MC:方法区大小
  • MU:方法区使用大小
  • CCSC:压缩类空间大小
  • CCSU:压缩类空间使用大小
  • YGC:年轻代垃圾回收次数
  • YGCT:年轻代垃圾回收消耗时间
  • FGC:老年代垃圾回收次数
  • FGCT:老年代垃圾回收消耗时间
  • GCT:垃圾回收消耗总时间

  可以看到发生了FullGC, MU 和 CCSU 都很大,FullGC并没有回收掉,再次确认了元空间内存溢出的可能。

1.4.2 打印类加载信息 分析代码

在JAVA_OPION 中添加 -verbose:class 打印类加载信息。重启后观察日志输出
在这里插入图片描述  发现以上输出信息,并且一直不停的Loaded。 打印出了相关的业务类.BusinessMessageBody、BusinessMessage ,看样子是使用Jaxb 序列化成XML时产生的问题。在项目中搜索相关代码。

总之,不是自己的案例,s省略中间的源码分析过程…,直接给结论:

因为框架这一行,会重复执行类的定义,一定重复定义,重复定义,在jvm内部会有一次约束检查出LinkageError,但临时创建的结构,等待GC去回收。

1.4.3 思考,并分析dump文件

  那么回过来想,为什么 injectors 被回收后,对应的Class实例未被回收卸载掉呢? 此现象产生的环境差异是因为升级了JDK版本,由JDK7升级到JDK8, 那么JDK8对垃圾回收做了哪些改变,是否这些改变导致了此问题的产生。带着这个疑问检索 google,得到了答案。

  在JDK 7中,对Permgen中对象的回收会进行存活性检查,因此重复定义时产生的数据会在GC时被清理。然而在JDK 8中,Metaspace的回收只依赖classloader的存活,当classloader还活着时,它所产生的对象无论存活与否都不会被回收,由此引发了OOM。

从生产环境dump出来的内存文件分析后验证了这一点:
在这里插入图片描述
参见 :
假笨说-谨防JDK8重复类定义造成的内存泄漏
JVM源码分析之JDK8下的僵尸(无法回收)类加载器
JAXB导致的Metaspace OOM问题分析

  JAXB-impl 2.2.11 版本 inject 版本种增加了一段 findLoadedClass`` 逻辑,按名称查找是否已有加载的类,避免重复定义加载。

二、入库内存泄露总结

  由于条件问题,一个查询语句把一个表里所有的记录都查询出来了,数据量很大,把内存打爆,
造成现场验收卡,卡,卡…

2.1 用jmap -dump命令导出JVM的整个内存信息。

在这里插入图片描述
快速定位报表里的泄露嫌疑犯,点击进去,如图,发现这两个嫌疑犯占用了
49.90%+44.45%=94,35%的内存,还让其他功能咋用呢??

在这里插入图片描述
在这里插入图片描述
点击第一个嫌疑犯的堆栈信息链接,仔细看就能发现该嫌疑犯是如何行凶的,如下图:
在这里插入图片描述
总结:内存分析工具有很多,使用MAT是其中的一种方法。另外,除了手动导出JVM内存信息外,还可以通过设置JVM参数,在JVM发生内存泄露的时候自动导出文件。

三、ArrayList递归调用addAll方法导致内存溢出

过程略,直接给结论:

  本段递归原思想以ids(ArrayList)为容器,循环添加每个子节点包含的全部分组id,并加上自身节点,进行返回。
  但是,由于ids为引用传递,每次addAll操作都会将容器中已有的ids重复添加到容器中,造成每次添加容器中的数据都会发生倍增。
  子分组数小时,不会发生异常现象。ArrayList 的每次扩容包括分配1.5倍的新数组空间,和老数组历史数据的拷贝。
  当子分组数超过27个时,数组长度达到了134217726,当长度超过Integer.MAX_VALUE-8或系统无法给ArrayList分配足够长的连续内存空间时,就会抛OOM异常。
  ArrayList的频繁扩容与拷贝操作,也导致了在执行递归方法开始到抛出OOM异常这段过程中,Cpu一直处于100%的状态,无法处理其它请求。

3.1 经验总结

  1. 在写完递归方法后,自测一定要认真测试到递归方法层的输入与返回,功能通过不能代表代码没有问题。
  2. 在使用ArrayList的时候,如果可以预知数组的大小范围,尽量对其进行容量大小的初始化,避
    免其频繁扩容。

四、读取excel引发的内存泄露

4.1 现象

  1. 业务反馈****.com打开显示502,去查logbook日志发现应用出现内存溢出;
    在这里插入图片描述
  2. 去ump中jvm监控查dump文件输入路径“-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/export/Instances/las-im-manager-new/server1/logs”,登录运维自主平台下载dump文件;
  3. 使用MAT工具打开dump文件,查看大对象的具体堆栈信息;
    在这里插入图片描述
  4. 去程序中查代码,excel导入读取是使用WorkBook的方式,经测试几兆的excel文件导入就占用大量的内存(超1g);
  5. 去查poi文档 http://poi.apache.org/spreadsheet/how-to.html ,发现POI提供了2中读取Excel的模式,分别是:
  • 用户模式:也就是poi下的usermodel有关包,它对用户友好,有统一的接口在ss包下,但是它是
    把整个文件读取到内存中的,对于大量数据很容易内存溢出,所以只能用来处理相对较小量的数据;
  • 事件模式:在poi下的eventusermodel包下,相对来说实现比较复杂,但是它处理速度快,占用内存少,可以用来处理海量的Excel数据;
  1. 参考了poi官方example( http://svn.apache.org/repos/asf/poi/trunk/src/examples/src/org/apache/poi/xssf/eventusermodel/examples/FromHowTo.java ),使用事件模式读取excel,解决了问题;

五、通用sql查询条件全if导致的内存溢出

5.1 现象:

  目前JVM启动日志中都配置了 内存打满前自动dump,前往对应的机器dump日志进行分析,使用工具为jprofiler,经过分析 发现byte类型占用了435MB的数据,并且调用来源为ibatis.executor.resultset.ResultWrapper,经过jprofiler分析,怀疑有全表查询语句 返回了大对象
导致的内存溢出。
在这里插入图片描述

5.2 查询对应数据库是否存在慢sql全表查询

问题sql:
在这里插入图片描述

5.3 修改方案: 针对Dao层对一些基础参数进行强制校验(三要素)

在这里插入图片描述

六、JVM堆栈内存溢出问题分析

6.1 分析JVM内存溢出时生成的hprof

关键数据:
JVM堆栈报告中:大对象:
在这里插入图片描述
大对象中的占用内存最大的属性:
在这里插入图片描述
未来得及释放的XML解析数据: 该数据已经导出,在后面:
在这里插入图片描述
线程调用的HTTP响应方法:
在这里插入图片描述
用户上传文件:
在这里插入图片描述

6.2 原因分析:

  在查看JVM内存堆栈信息分析报告的,Orverview的大对象图表中,说名称为"http-1601-18"的线程事例时占用内存超过2G;继而查看该线程实例包含属性实例明细列表;

  发现线程中占用内存最大的实例类为:
com.sun.org.apache.xerces.internal.dom.DeferredDocumentImpl ,占用内存 2G 左右;初步可以确定此实例的创建造成了JVM内存溢出;
  而该实例是POI工具包用于解析xlsx格式文件中的XML文件用的,也就是说是因为该线程执行过程中需要有xlsx文件解析逻辑。

进而查询该线程的调用HTTP业务接口,是:
com…master.goods.controller.GoodsNewController#importBatGoods ;
结合代码,获知此方法是用于批量导入事业部商品数据的,其大致逻辑是:

  1. 接收用户导入的xlsx文件
  2. 使用POI包对文件进行解析
  3. 循环遍历解析后的数据,对他们进行数据验证、数据入库(及创建商品)操作
  4. 返回导入结果

  结合的代码逻辑,堆栈信息分析,初步结论为某一用户在执行改操作时,导入了过大文件,导致此次的JVM 内存溢出事故;
然后查询四台主机操作日志:果然发现同一个用户在每次告警前的几分钟,都在商家工作台执行了商品导入操作;

  因而得出本次JVM内存溢出的最终原因为:系统并未对导入文件大小做限制或限制太宽松; 从而导致用户导入较大的文件时在解析过程中出现 JVM内存溢出问题;

  因而得出本次JVM内存溢出的最终原因为:系统并未对导入文件大小做限制或限制太宽松; 从而导致用户导入较大的文件时在解析过程中出现 JVM内存溢出问题;

6.3 问题修复方案

  1. 对上传得文件进行大小限制;限制的原则就是根据模板和数据条目上限,计算出一个合理的数值;根据实践:1000条的数据文件大小约在135K,5000条的文件大小在619K;也就是说文件大小不应该超过1M;而本案例中,用户上传的文件大小在26M左右;
  2. 解析数据时,要先进行数据行数验证,在对行数据进行解析;尽量减少数据转换次数;

七、生产环境部分机器内存溢出问题处理

7.1 现象

  部分请求出现502的情况。经查看发现5台服务器中的一台宕机,Tomcat进程已经不存在了。

  对该服务器及负载下的其他服务器的运行状态进行观察发现:该服务器的jvm已经没有数据,其他服务器jvm内存均接近100%,看来其他服务器也岌岌可危啊。

  查看了下宕机的那台服务器日志,关键信息如下:
在这里插入图片描述
  为了查看该日志文件,和jdos同事,申请开通了 该服务器 和 另外一台濒临崩溃的服务器的 终端连接信息;

  该文件信息基本上全是当时崩溃是的内存的一些大小参数(忘记截图),参考意义不大;

7.2 分析

  紧接着为了查看内存中到底是什么对象导致了内存的崩溃,由于jvm崩溃了,获取不到现在的一些信息了,于是连接到另外一台“濒危”的服务器上,去查看jvm内存的一些状况,具体情况如下:

  1. 首先使用查看了下 jvm进程ID为 139;
  2. 使用该命令 :sudo -u admin ./jmap -histo 139|more 查看到的情况如下:
    在这里插入图片描述
     如图:有31889个“Thread”事例导致,初步分析,某个地方在疯狂创建线程。但是,在哪个地方创建呢?我和几个相关同事沟通,确定没人在这个项目里边创建过线程。

 其实这个时候离成功仅有一步之遥了。

  1. 正在兴奋的解决中,杨xx同学也参与进来建议用sudo -u admin ./jstack -l -F 139 > stack.txt 打印堆栈信息,如图:
    在这里插入图片描述
    查到有7000多个线程池,可以定位某个地方在疯狂创建线程池,肯定了第一步的判断。

  2. 然后全文搜 Executors,发现之前的同事有两处创建线程池,并且是每次该请求接口基本上都会创建一个固定4个大小的线程池!原因终于找到了;此处列举一处:
    在这里插入图片描述

  3. 于是,将宕掉的机子重启,然后频繁的去请求该接口,复现了异常情况,由此可以肯定了判断。此处修改为启动的时候创建一个线程池,请求的时候创建一个Callable实现即可。

续:补上此次服务器的jvm参数,以及dump文件大小
在这里插入图片描述
使用命令 sudo -u admin ./jmap -dump:format=b,file=a.hprof 139

7.3 事故反思总结

  1. 将服务器监控预警做到位,此次疏于预警,导致服务器异常,没有及时发现,而是由业务方通知发现的,以后应避免此类事情再次发生。
  2. 多人合作项目,项目时间长一些细节东西已经记的不清晰了,以后重要的设计点最好有设计问题,方便后人解决问题。
  3. 有必要进行codeReview,来相互学习,相互进步。
  4. 应继续加强深入学习jvm相关知识,此处的事故算是一个在学习jvm道路上的一个成功解决案例。

八、JVM异常终止问题排查

8.1 现象

jdos两台机器JVM突然挂掉(11.26.78.xx、10.190.183.xx),查看MDC监控,发现jvm挂掉的时间点 机器内存占用很高(99%);
内存很平稳,每次yong gc,都能降下来;至JVM挂掉之前,未触发过full gc;CPU和线程数也都很正常。

8.2 问题初步分析定位-尝试Google

在这里插入图片描述

8.3 linux的OOM killer

 Linux 内核有个机制叫OOM killer(Out-Of-Memory killer),该机制会监控那些占用内存过大,尤其是瞬间很快消耗大量内存的进程,为了防止内存耗尽而内核会把该进程杀掉。 因此,你发现java进程突然没了,首先要怀疑是不是被linux的OOM killer给干掉了!

OK,顺着这个思路,确定到底是不是被oom killer干掉的。

查看系统报错日志: /var/log/messages,发现此文件是空的(后来咨询jdos运维同事得知,docker实例写此日志被禁用)
在这里插入图片描述
查看内核日志:
在这里插入图片描述
dmesg输出信息有调用oom-killer,但是从内存来看貌似是宿主机的(totalvm:22120752kB),时间点无法确定;

联系运维查询:
在这里插入图片描述
在这里插入图片描述
可以确定JVM是被操作系统oom killer干掉了。

问题:docker规格4c4g,为何java进程会占用5.2g?

jdk1.8及之前,JVM是感知不到容器的存在的,所以会使用宿主机的信息来计算,docker -m参数一般用来限制应用内存大小,跟镜像版本也有很大关系,有的版本限制的差不多相当于物理内存的 百分之50。
模拟:OOMKilled

九、其他

上面两个案例说明一个问题:遇见jvm异常退出,先找dump文件,dump如果没有,找hs_err_pid.log日志。如果还没有,翻内核日志。

jvm建议配置:

以8G内存为例:
1-垃圾回收器的参数
2-元空间需要配?512,350
3-堆内存最大最小?4G
4-栈大小?512k
5-直接物理内存?
6-GC日志

不建议配置的: 各个区域的比例,默认值。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

从零开始怎么做好产品宣传册

​随着市场竞争的日益激烈,产品宣传册作为企业与消费者之间的桥梁,其重要性日益凸显。一份优秀的宣传册不仅能提升企业的品牌形象,还能帮助企业更好地推广产品,吸引潜在客户。然而,很多企业在制作宣传册时却常常无从下…

分析一个项目(微信小程序篇)三

目录 接下来分析接口方面: home接口: categories接口: details接口: login接口: 分析一个项目讲究的是如何进行对项目的解析分解,进一步了解项目的整体结构,熟悉项目的结构,能够…

父组件中 arr.push改变数组,但是子组件监听不到 arr 的变化

目录 一、问题 二、解决方法 三、总结 tiips:如嫌繁琐,直接移步总结即可! 一、问题 1.真是奇怪呀,一般来说通过 push方法改变 数组,是一定会有响应式的,那就可以监听到变化。但是我今天却遇到了一件奇怪的事情。在…

如何挑选合适的106短信群发平台?(建议详细看)

日常生活中,我们经常收到以106开头的短信,这些短信大多都是通过106短信群发平台发出来的,106短信是指基于中国移动、联通和电信直接提供的短信端口与互联网连接,实现与客户指定号码进行短信批量发送和自定义发送。 一般而言&#…

图鸟引入多套字体图标的方式教程

https://www.yuque.com/tuniao/qunyou/tgfvpg ①上传icon,生成iconfont.css 将css文件放这里 app.vue全局引入 适当改造iconfont.css的写法,方便调用

【卡梅德生物】单B细胞技术:牛单抗制备

1.牛单B细胞技术原理 单个B细胞抗体制备技术是近年来新发展的一类快速制备单克隆抗体的技术,基于流式细胞分选技术进行单B细胞单抗制备,利用每个B细胞只含有一个功能性重链可变区DNA序列和一个轻链可变区DNA序列且只产生一种特异性抗体的特性&#xff0c…

架构03 - 理解构架的视角

学习架构时,首要任务是弄清楚不同视角对于架构的理解,因为每个人对于架构的理解可能存在差异。不同职位对于架构的关注点也不同。开发人员更多关注开发架构,售前人员更多关注业务架构,运维人员更多关注运维架构,技术支…

供排水管网管理信息化的必要性

供排水管网是城市供水系统的大动脉,它负担者将优质水源输送到最终用户的重要职责,对供水系统有着极其重要的作用。城市供排水管网埋设在地下,规模庞大,仅靠人工难以管理。同时,由于城市的发展,管网连接结构…

云防护概念及云防护作用

云防护是什么 云防护是一种网络安全技术,旨在保护云计算环境中的数据和系统免受恶意攻击和未授权访问。 云防护适用场景 一切http.https.tcp协议,如游戏、电商、金融、物联网等APP PC 网站。 云防护的主要作用 云防护的主要作用是通过搭规模庞大的云防…

Android studio第一次构建项目Gradle失败的解决方法

每次在AS上新创建一个项目,gradle要下载半天或者是直接下载半天后以失败告终,抓狂并崩溃。 原因: 这是因为AS默认去下载gradle的网站是在国外的,而且国内的网络经常是访问不到那个网站的,能访问到有时候就跟中大奖一…

linux下带宽和流量的统计

目录 1)iperf3带宽测试2)ifstat网口流量监控 1)iperf3带宽测试 主要用于带宽的测试。 iperf3 -s开启服务 iperf3 -c 服务器ip地址 -t 65535 关注的几个点 1.网卡自动协商的带宽,比如路由是100Mbps或1000Mbs,查看方…

Linux学习(3):查找指令、压缩和解压

Linux学习(3):查找指令、压缩和解压 1 查找指令1.1 find 查找1.2 locate 快速定位路径1.3 which 检索指令在哪个目录下1.4 grep 过滤查找 2 压缩和解压2.1 gzip压缩 & gunzip解压2.2 zip & unzip (文件或文件夹)2.3 tar 打包 1 查找指…

【STM32】HAL库的STOP低功耗模式UART串口唤醒,解决首字节出错的问题(全网第一解决方案)

【STM32】HAL库的STOP低功耗模式UART串口唤醒,解决首字节出错的问题(全网第一解决方案) 前文: 【STM32】HAL库的STOP低功耗模式UART串口唤醒,第一个接收字节出错的问题(疑难杂症) 目前已解决 …

AMEYA360:广和通RedCap模组FG131FG132系列

2024年1月,广和通RedCap模组FG131&FG132系列已进入工程送样阶段,可为终端客户提供样片。广和通RedCap模组系列满足不同终端对5G速率、功耗、尺寸、成本的需求,全面助力RedCap技术的行业应用。 FG131&FG132系列基于骁龙X35 5G调制解调…

贝叶斯优化的基本流程

贝叶斯优化的基本流程 假设已知一个函数𝑓(𝑥)的表达式以及其自变量𝑥的定义域,现在,我们希望求解出𝑥的取值范围上𝑓(𝑥)的最小值,你打算如何求解这个最小值呢&#xf…

创新奖肯定,这家LIMS您要留意了

近日,龙源电力的“风电化学监督LIMS信息化管理系统的研发与应用”项目荣获中国电力技术市场协会2023年电力行业技术监督创新成果一等奖。系统可为风电设备经济、环保、长周期安全运行提供保障,是国内首套新能源行业油液监测信息管理系统,经中…

函数式编程 - 组合compose的使用方法

函数式编程中有一个比较重要的概念就是函数组合(compose),组合多个函数,同时返回一个新的函数。调用时,组合函数按顺序从右向左执行。右边函数调用后,返回的结果,作为左边函数的参数传入,严格保…

LeetCode刷题--- 按摩师

个人主页:元清加油_【C】,【C语言】,【数据结构与算法】-CSDN博客 个人专栏 力扣递归算法题 http://t.csdnimg.cn/yUl2I 【C】 ​​​​​​http://t.csdnimg.cn/6AbpV 数据结构与算法 ​​​http://t.csdnimg.cn/hKh2l 前言:这个专栏主要讲述动…

STM32--基于STM32F103的MAX30102心率血氧测量

本文介绍基于STM32F103ZET6MAX30102心率血氧测量0.96寸OLED(7针)显示(完整程序代码见文末链接) 一、简介 MAX30102是一个集成的脉搏血氧仪和心率监测仪生物传感器的模块。它集成了一个红光LED和一个红外光LED、光电检测器、光器…

瑞吉外卖笔记系列(1) —— 环境配置,后台登录和退出的功能实现

本文档主要介绍软件开发整体流程和瑞吉外卖项目,开发环境搭建步骤,以及简单的后台系统功能实现 文章目录 一、软件开发整体介绍1.1软件开发流程1.2 角色分工1.3 软件环境 二、瑞吉外卖项目介绍2.1 项目介绍2.2 产品原型展示2.3 技术选型2.4 功能架构2.5 …