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

news2025/2/26 13:22:07

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

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

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日志

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

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

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

相关文章

[笔记]学习做微信小程序

学习视频:前端微信小程序开发教程 本篇文章 只对关键内容笔记,用于自用。 这里写目录标题 注册、下载、安装我的小程序ID:wxe1fbd6939d8797d8我的小游戏ID:wx8b2c3e47ac9127b7开发者工具外观代理设置 创建第一个小程序主界面5个组…

智能合约笔记

前言: 首先了解下为什么会出现智能合约,打个比方现在有两个人A和B打赌明天会不会下雨,每个人赌注100元,如果第二天下雨则A拿走200元,否则B拿走200元,这样就有一个问题,赌注要到第二天才能见效&…

[算法与数据结构][c++]:Static关键字和全局变量

Static关键字和全局变量 1. 生命周期、作用域和初始化时机2. 全局变量3. Static 关键字3.1 面向过程3.1.1 静态全局变量3.1.2 静态局部变量(单例中会使用)3.1.3 静态函数 3.2 面向对象3.2.1 类内静态成员变量3.2.2 类内静态成员函数 Reference 写在前面&…

Springboot药物不良反应智能监测系统源码

一、系统简介 ADR指的是药品不良反应,即在合格药品在正常用法用量下,出现与用药目的无关或意外的有害反应。ADR数据辨别引擎、药品ADR信号主动监测引擎、ADR处置行为分析引擎。ADR数据辨别引擎,通过主动监测患者具象临床指标,比如…

作业:通过两台linux主机配置ssh实现互相免密登陆

做题步骤: 一.开启两个Linux主机,并且用ssh连接,要能够ping通 我这里是server:192.168.81.129 client:192.168.81.130 举例 步骤: 1.安装服务软件 2.运行软件程序 3.根据自定配置提供对应的服务/etc/chr…

centOS系统yum安装和卸载mongodb

0.1 什么是mongodb? 0.2 Mongodb是一个基于分布式文件存储的数据库。由C语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。 0.3 Mongodb是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据…

WEB之HTML练习

第一题&#xff1a;用户注册界面 HTML代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><titl…

C++游戏引擎中的坐标系

一.Direct3D四大变换 <1.世界矩阵变换: 为了模拟3D物体的旋转,缩放,平移等功能,Direct3D将静态模型的顶点坐标x,y,z经过旋转平移矩阵变换以得到新的顶点坐标x1,y1,z1 D3DXMATRIX mTrans ; D3DXMatrixTranslation (&mTrans , 5 , - 3 , 0 ); g_pd3dDevice->SetTr…

Avalonia学习(二十)-登录界面演示

今天开始继续Avalonia练习。 本节&#xff1a;演示实现登录界面 在网上看见一个博客&#xff0c;展示Avalonia实现&#xff0c;仿照GGTalk&#xff0c;我实现了一下&#xff0c;感觉是可以的。将测试的数据代码效果写下来。主要是样式使用&#xff0c;图片加载方式。 只有前…

移远通信推出两款Wi-Fi 7模组新品,赋能无线连接巅峰体验

​1月9日&#xff0c;在2024年国际消费电子产品展览会 (CES) 期间&#xff0c;全球领先的物联网整体解决方案供应商移远通信宣布&#xff0c;正式推出支持Wi-Fi 7技术的通信模组FGE576Q和FGE573Q &#xff0c;这两款模组将以前沿的Wi-Fi性能突破无线连接边界&#xff0c;为下一…

JVM工作原理与实战(十二):打破双亲委派机制-自定义类加载器

专栏导航 JVM工作原理与实战 RabbitMQ入门指南 从零开始了解大数据 目录 专栏导航 前言 一、打破双亲委派机制的方法 二、自定义类加载器 1.Tomcat自定义类加载器案例 2.自定义类加载器详解 3.案例解析 总结 前言 JVM作为Java程序的运行环境&#xff0c;其负责解释和执…

探索未来餐饮:构建创新连锁餐饮系统的技术之旅

随着数字化时代的发展&#xff0c;连锁餐饮系统的设计和开发不再仅仅关乎订单处理&#xff0c;更是一场充满技术创新的冒险。在本文中&#xff0c;我们将深入研究连锁餐饮系统的技术实现&#xff0c;带你探索未来餐饮业的数字化美食之旅。 1. 构建强大的后端服务 在设计连锁…

windows安装Elasticsearch后使用ik分词器报错解决办法

最近在学习Elasticsearch&#xff0c;安装完成后下载了ik分词器压缩到plugins目录下启动es报错如下&#xff1a; java.security.AccessControlException: access denied (“java.io.FilePermission” “D:…\plugins\ik-analyzer\config\IKAnalyzer.cfg.xml” “read”)咋一看…

k8s的存储卷、数据卷

容器内的目录和宿主机目录进行挂载。 容器在系统上的生命周期是短暂的。 k8s用控制器创建的pod。delete相当于重启。容器的状态也会恢复到初始状态。一旦恢复到初始状态&#xff0c;所有的后天编辑的文件都会消失 容器和节点之间创建一个可以持久化保存容器内文件的存储卷。…

OpenCV-21方盒滤波和均值滤波

一、方和滤波 使用API --- boxFiter(src, ddepth, ksize[,dst[,anchor[, normalize[, borderType]]]])方盒滤波 方盒滤波的卷积核如下所示&#xff1a; --- normalize Ture时&#xff0c; a 1 / &#xff08;W*H&#xff09;滤波器的宽高 --- normalize False时&#xff…

【大数据OLAP引擎】StartRocks存算分离

存算分离的原因 降低存储成本&#xff1a;同样的存储大小对象存储价格只有SSD的1/10&#xff0c;所以号称存储成本降低80%不是吹的。 存算一体到存算分离 存算一体 作为 MPP 数据库的典型代表&#xff0c;StarRocks 3.0 版本之前使用存算一体 (shared-nothing) 架构&#xf…

mysql主从复制教程

1、介绍 1.1 是什么 主从复制&#xff0c;是用来建立一个和主数据库完全一样的数据库环境&#xff0c;称为从数据库 1.2 有什么用 数据备份&#xff1a;通过主从复制&#xff0c;可以将主数据库的数据复制到一个或多个从数据库中&#xff0c;以实现数据备份和灾难恢复。当主…

免费简单好用的 webshell 在线检测:支持 php、jsp、asp等多格式文件

话不多说&#xff0c;直接上图上链接&#xff1a;https://rivers.chaitin.cn/?share3d4f2e8aaec211eea5550242c0a8170c 还是比较好用的&#xff0c;支持 PHP、JSP 文件 webshell 检测&#xff0c;看官方解释文档&#xff0c;引擎使用静态文本特征、骨架哈希、静态语义分析、动…

【Github-Action】GithubAction 环境下,如何将临时生成的文件推送至指定分支。

通过这篇文章你可以掌握如何将github action 环境下临时生成的文件推送至指定分支&#xff0c;并且可以打开利用github开放的api做各种强大或有趣的事情的视野和思路。 如果你对github-action感兴趣&#xff0c;还可以看这篇文章&#xff0c; 这篇文章教会你如何开发Github Act…

多局域网UDP通信测试

今天遇到一个问题&#xff1a; 一台电脑同时连接A、B两个路由器的网络&#xff0c;同时分别收发各自局域网中的消息&#xff0c;是否可行&#xff1f; 理论上可以&#xff0c;测试一下吧 电脑同时连接两个网络 两个网络的网段分别为3和1 在同一个程序中使用两个网络连接的地…