当前位置: 首页 > news >正文

JVM内存溢出问题排查

内存溢出 out of memory : 通俗理解就是内存不够用了,是我们工作当中经常会遇到的问题,内存溢出有可能发生在正常的情况下,而非代码层面问题导致,比如高并发下,大量的请求占用内存,垃圾回收机制无法进行回收,而导致的内存溢出,这种情况就需要我们去调整架构了。一但出现内存溢出问题,我们需要快速定位并解决,尤其是生产环境,所以针对内存溢出问题,我们需要掌握一些常用的排查工具,针对不同场景、现象有快速排查思路。引起内存溢出的原因有很多种,常见的有以下几种:

● 内存中加载的数据量过于庞大,如一次从数据库取出过多数据;

● 资源使用之后没有及时关闭,导致对象无法被GC回收;

● 代码中存在死循环或循环产生过多重复的对象实体;

● 使用的第三方软件中的BUG;

● 启动参数内存值设定的过小;

排查辅助技术介绍

01

排查内存问题的常用命令:

● Jps:是java提供的一个显示当前所有java进程pid的命令

● Jstat 命令:查看堆内存各部分的使用量,加载类的数量以及GC的情况

● Jstack命令:主要是用来查看java线程的堆栈信息,分析线程有没有死锁,比如下面的这个两个线程互相等待对方释放锁而产生的死锁信息

● Jmap:主要是用来dump java进程内存快照的,便于我们去分析内存中对象的存储情况

02

内存文件分析工具:

● MemoryAnalyzer:这是一款Eclipse提供的内存分析工具,可以结合Eclipse使用,也可独立使用

● JProfiler,:这是由ej-technologies GmbH公司开发的一款内存分析工具,可以结合IDEA使用

● Jconsole:是一个用java写的GUI程序,用来监控VM,并可监控远程的VM

案例说明

正常情况下,我们生产环境都会配置监控措施,服务器资源比如CPU、内存的使用达到我们预设的报警阈值,就会触发报警,提示我们相应的维护人员,这时我们开发人员就需要快速定位原因,采取相应措施。下面结合我之前的一个例子来说下:

1.一天晚上19点30左右线上32服务器开始持续出现cpu占用率高的现象,最高已达到90%左右,同时伴随的其他现象还有内存占用率稍高,达到60%左右,因为当时监控配置的是机器的监控,并没有直接收到java服务内存溢出的报警,所以当时是从cpu异常开始排查。

2.收到报警后,第一感觉存在代码死循环,或者请求线程太多。但这个时间点请求量很少,也没有修改过代码。

3.cpu占用率高基本和进程/线程有关,使用top查看一下cpu占用率高的进程,进程id是18713

18713正是系统的跑批服务器,查看日志发现19:30左右执行了上传文件到oss服务器的批量任务,查看日志发现在下午执行了20几次

4.使用top -H -p 18713查看cpu占用率高的线程,存在4个

5.将这四个线程的线程id转换成16进制打印,分别是4922,4923,4924,4925

6.使用jstack -l 18713>> a.txt进行线程dump,如有必要可以多输出几次。根据上面4个线程的线程id在文件中查找,找到4条线程日志

注意这四个线程是jvm垃圾回收线程,不是业务线程。

7.接着使用jstat -gc 18713 5000打印垃圾回收日志进行确认,发现jvm很短时间内进行了多次的fullgc操作

8.此时基本确定存在垃圾回收问题,只是还没有导致内存溢出,虽然线上配置了jvm溢出之后进行内存dump,但此时内存占用只有60%。

9.只能使用jmap -dump:file=dump.hprof 18713强制进行一次内存dump。导出文件到本地目录,文件通常会很大。所以建议jvm堆内存上限不要设置的太大。否则内存分析工具分析也成问题。

  1. 下载MemoryAnalyzer内存分析工具,其他工具也可以。配置下MemoryAnalyzer.ini文件,将内存调的大一点,否则无法进行分析。

  1. 导入dump文件,时间稍长,慢慢等待。导入后有各种详细的展示视图。比如大对象,数量多的对象,泄露猜测等。

  1. 发现占用内存90%多的是http连接对象,点击查询引用明细,发现是oss依赖库引用了大量http连接对象

  1. 结合19:30左右的批量执行情况推断,这个批量存在内存泄露,使用后没有及时释放连接,造成内存占用率高,而垃圾回收在回收这部分内存的时候又造成了cpu占用率高。这次跑批的次数有点多。

  2. 排查代码发现果然如此:ossClient对象使用后没有关闭

  1. 修复代码之后,再次重启跑批,发现问题也得到了解决。

总结

当然,分析和解决内存溢出相关问题的步骤,不是固定的,还需要根据实际情况去做调整,止损是第一位的,正常情况我们需要快速重启的先,重启可以使服务快速恢复,但是只重启,指标不治本,如果没有定位到溢出的原因,重启一段时间可能又会溢出。所以一定要留存排查依据,比如内存文件,线程的文件等。留存内存文件有两种方式:一是配置jvm启动参数: -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=xxxx(文件导出路径),JVM发生OOM时,自动生成dump文件;二是采用jmap命令,手动进行内存dump。

更多技术文章

相关文章:

  • java计算机毕业设计门诊药品管理系统源码+数据库+系统+lw文档+mybatis+运行部署
  • 真知灼见|客户视图与工作台:金融行业呼叫中心领域驱动设计
  • spring-task进行任务调度
  • npm实现格式化时间---就是实现时间按照要求输出--moment包
  • webdriver API进阶
  • 除自身以外数组的乘积、找到所有数组中消失的数字、两数之和
  • 四川农信分布式核心设计及验证项目成果专家评审会召开
  • 快速知识蒸馏的视觉框架-来自卡耐基梅隆大学等单位
  • c++ 11 线程支持 (std::promise)
  • 一篇文章带你看清C语言中的类型转换规则
  • 单海军:行业AI平台赋能金融企业数智化转型
  • Jmeter接口自动化(十)断言
  • C++ 小游戏 视频及资料集(7)
  • 计算机网络笔记(王道考研) 第二章:物理层
  • TCP的连接过程——三次握手和四次挥手
  • 【面试系列】之二:关于js原型
  • AHK 中 = 和 == 等比较运算符的用法
  • CSS实用技巧
  • egg(89)--egg之redis的发布和订阅
  • exports和module.exports
  • gcc介绍及安装
  • Golang-长连接-状态推送
  • Hexo+码云+git快速搭建免费的静态Blog
  • iOS仿今日头条、壁纸应用、筛选分类、三方微博、颜色填充等源码
  • Laravel Mix运行时关于es2015报错解决方案
  • Linux CTF 逆向入门
  • React组件设计模式(一)
  • Sequelize 中文文档 v4 - Getting started - 入门
  • SQLServer之创建显式事务
  • 大型网站性能监测、分析与优化常见问题QA
  • 规范化安全开发 KOA 手脚架
  • 计算机在识别图像时“看到”了什么?
  • 简单实现一个textarea自适应高度
  • 猫头鹰的深夜翻译:Java 2D Graphics, 简单的仿射变换
  • 漂亮刷新控件-iOS
  • 什么是Javascript函数节流?
  • 手写双向链表LinkedList的几个常用功能
  • 小程序、APP Store 需要的 SSL 证书是个什么东西?
  • 一个JAVA程序员成长之路分享
  • 原生JS动态加载JS、CSS文件及代码脚本
  • 【干货分享】dos命令大全
  • ​如何在iOS手机上查看应用日志
  • #### go map 底层结构 ####
  • #Lua:Lua调用C++生成的DLL库
  • #宝哥教你#查看jquery绑定的事件函数
  • (MATLAB)第五章-矩阵运算
  • (免费领源码)Java#ssm#MySQL 创意商城03663-计算机毕业设计项目选题推荐
  • (区间dp) (经典例题) 石子合并
  • (四)库存超卖案例实战——优化redis分布式锁
  • (算法)Game
  • (原創) 如何使用ISO C++讀寫BMP圖檔? (C/C++) (Image Processing)
  • (转) 深度模型优化性能 调参
  • (转)jdk与jre的区别
  • ./indexer: error while loading shared libraries: libmysqlclient.so.18: cannot open shared object fil
  • .gitignore