记一次线上OOM问题分析与解决
一、问题情况
最近用户反映系统响应越来越慢,而且不是偶发性的慢。根据后台日志,可以看到系统已经有oom现象。
根据jdk自带的jconsole工具,可以监视到系统处于堵塞时期。cup占满,活动线程数持续增加,堆内存接近峰值。
二、分析情况
使用jconsole分析:
找到jdk安装路径,点击bin目录下的jconsole.exe,运行。
当时线上情况是堆内存使用量7个G左右,接近峰值;活动线程80个左右;CPU占用率80%左右。系统随时可能宕机。
根据用户反映的情况,系统每隔一段时间都会卡顿,且堆内存是一段时间上升,然后突然下降,再上升,所以我第一反应是:会不会是系统频繁的进行FullGC,导致系统在一段时间内不可用?
首先认识一下什么是Full GC(需要一定的java内存模型知识):
含义:FullGC是发生在永久代和老年代的一种垃圾回收机制。
触发条件:老年代内存满时。
特点:执行时间长,期间系统不可用。
于是查看老年代占用情况:
使用期间老年代内存峰值已经达到7个G左右,接近上限。貌似有点坏气息的味道。
于是用jstat -gc pid查看gc回收情况:
案发当时Full GC执行次数为28次,总执行时长为27秒。可以实锤是频繁Full GC导致系统线程堵塞。
上面介绍到了,老年代内存满时会触发FullGC,那么哪种情况下会进入老年代呢?
(1)对象在新生代中经历固定次数minor GC,会进入老年代
可通过-XX:MaxTenuringThreshold设置,默认15
(2)当新生代中minor GC回收后,存活对象大于survivor to区容量时,进入老年代
(3)大对象直接进入老年代
可通过-XX:PretenureSizeThreshold 设置
使用jvisualvm分析:
在jdk的bin目录下,找到jvisualvm.exe,点击运行。
这里可以很清楚的看到堆内存的内容分布情况。当时系统是byte[]和InternalAprOutputBuffer占用内存最大,同为2.9G。
在此不能很直观的分析具体原因,建议使用Eclipse的Mat插件进行分析。
放上Mat插件的安装教程:https://mp.csdn.net/postedit/103815484
放上系统当时的Dump:
问题就在于这两处占用太多堆内存。
接着我们去查看Dominator Tree,可以查看到保持存活的最大对象集合
至少有一半都是InternalAprOutputBuffer对象。Shallow Heap 表示原本大小,Retained Heap表示在堆中占用内存的大小,单位bytes(1kb = 1024bytes),每个对象在堆中占约47.6兆空间,难以想象。
那么这些对象里都是些什么内容呢?为什么会这么多?
点开树形,发现内容就是这个容量为50000000的byte数组。
再看看左边的Attributes值,的确有50000000的长度,那里面到底存放的是那些数据呢?
点击图片右下角的加号,展开数据,发现只有前面的几百条有数据,后面的一直到50000000都是0。意思就是实际byte[]中只有311条为有效值,其余都是以0填充的,且占用了几千万个值,造成了内存的暴涨。
再结合org.apache.coyote.http11.InternalAprOutputBuffer类是Tomcat的一个类,猜想是不是跟Tomcat的配置有关,于是打开Tomcat的server.xml一探究竟。
有没有觉得这50000000很眼熟?就是这个byte[]的长度。
那么为什么要设置这个参数呢?
据同事说,加这个参数是为了解决get请求中url参数过长,超大而报错的问题。
但是,各大浏览器均对url的长度有所限制,而且这个值在Tomcat中默认是4K,这里大约都是50M了,所以为了解决问题,最后把这里改成了8K,就是8192,然后再修改接口,参数过大的查询用Post去请求。
至此,问题解决,服务器运行顺畅,没有再出现卡死的情况。
记一次线上OOM问题分析与解决的更多相关文章
- 记一次线上 OOM 和性能优化
大家好,我是鸭血粉丝(大家会亲切的喊我 「阿粉」),是一位喜欢吃鸭血粉丝的程序员,回想起之前线上出现 OOM 的场景,毕竟当时是第一次遇到这么 紧脏 的大事,要好好记录下来. 1 事情回顾 在某次周五 ...
- 记一次线上频繁fullGc的排查解决过程
发生背景 最近上线的一个项目几乎全是查询业务,并且都是大表的慢查询,sql优化是做了一轮又一轮,前几天用户反馈页面加载过慢还时不时的会timeout,但是我们把对应的sql都优化一遍过后,前台响应还是 ...
- 一次线上OOM故障排查经过
转贴:http://my.oschina.net/flashsword/blog/205266 本文是一次线上OOM故障排查的经过,内容比较基础但是真实,主要是记录一下,没有OOM排查经验的同学也可以 ...
- 记一次线上bug排查-quartz线程调度相关
记一次线上bug排查,与各位共同探讨. 概述:使用quartz做的定时任务,正式生产环境有个任务延迟了1小时之久才触发.在这一小时里各种排查找不出问题,直到延迟时间结束了,该任务才珊珊触发.原因主要就 ...
- 【转】又一次线上 OOM 排查经过
又一次线上OOM排查经过 最近线上一个服务又出现了频繁Full GC的情况,导致提供的业务经常超时.问题出现非常不稳定,经过两周的时候,终于又捕捉到了一次Full GC,于是联系运维做Heap Dum ...
- 解Bug之路-记一次线上请求偶尔变慢的排查
解Bug之路-记一次线上请求偶尔变慢的排查 前言 最近解决了个比较棘手的问题,由于排查过程挺有意思,于是就以此为素材写出了本篇文章. Bug现场 这是一个偶发的性能问题.在每天几百万比交易请求中,平均 ...
- 火山引擎MARS-APM Plus x 飞书 |降低线上OOM,提高App性能稳定性
通过使用火山引擎MARS-APM Plus的memory graph功能,飞书研发团队有效分析定位问题线上case多达30例,线上OOM率降低到了0.8‰,降幅达到60%.大幅提升了用户体验,为飞书的 ...
- 记一次log4j日志导致线上OOM问题案例
最近一个服务突然出现 OutOfMemoryError,两台服务因为这个原因挂掉了,一直在full gc.还因为这个问题我们小组吃了一个线上故障.很是纳闷,一直运行的好好的,怎么突然就不行了呢... ...
- 记一次ArrayList产生的线上OOM问题
前言:本以为(OutOfMemoryError)OOM问题会离我们很远,但在一次生产上线灰度的过程中就出现了Java.Lang.OutOfMemoryError:Java heap space异常,通 ...
随机推荐
- 2020-07-31:给定一个二叉搜索树(BST),找到树中第K 小的节点。
福哥答案2020-07-31: BST 的中序遍历是升序序列.1.递归法.时间复杂度:O(N),遍历了整个树.空间复杂度:O(N),用了一个数组存储中序序列.2.迭代法.时间复杂度:O(H+k),其中 ...
- 2020-07-06:一个6亿的表a,一个3亿的表b,通过外间tid关联,你如何最快的查询出满足条件的第50000到第50200中的这200条数据记录
福哥答案2020-07-06:表a和表b的字段都是id和tid,数据类型都是int.查询结果顺序上以 表a 为准.1.JOIN.SELECT * FROM a JOIN b ON a.tid = b. ...
- Vue Elementui 表单必填项和非必填项label文字对齐的简单方式
1. 不好的方式 很长时间以来都是用改写form-item样式来使得必填项和非必填项保证label对齐,这样需要改写系统样式,还要在相应的item上引用,代码量增多,示例如下(不推荐) <tem ...
- 支持向量机SVM介绍
SVM为了达到更好的泛化效果,会构建具有"max-margin"的分类器(如下图所示),即最大化所有类里面距离超平面最近的点到超平面的距离,数学公式表示为$$\max\limits ...
- Spring/Springboot——JavaConfig
1.认识JavaConfig JavaConfig是Spring的一个子项目,在Spring4之后成为一个核心功能 JavaConfig中使用的注解: @Configuration 在类上打上这一标签 ...
- 图论算法(三) 最短路SPFA算法
我可能要退役了…… 退役之前,写一篇和我一样悲惨的算法:SPFA 最短路算法(二)SPFA算法 Part 1:SPFA算法是什么 其实呢,SPFA算法只是在天朝大陆OIers的称呼,它的正统名字叫做: ...
- SpringSecurity权限管理系统实战—四、整合SpringSecurity(上)
目录 SpringSecurity权限管理系统实战-一.项目简介和开发环境准备 SpringSecurity权限管理系统实战-二.日志.接口文档等实现 SpringSecurity权限管理系统实战-三 ...
- PythonCrashCourse 第九章习题
创建一个名为Restaurant 的类,其方法__init__() 设置两个属性: restaurant_name 和cuisine_type 创建一个名为describe _restaurant ( ...
- 3.MongoDB恢复探究:为什么oplogReplay参数只设置了日志应用结束时间oplogLimit,而没有设置开始时间?
(一)问题 在使用MySQL数据库binlog日志基于时间点恢复数据库时,我们必须要指定binlog的开始位置和结束位置,而在MongoDB里面,如果使用oplog进行恢复,只有oplogLimit参 ...
- (转)@Autowired(required=false)注入注意的问题
1.前言 在使用spring开发过程中,我们基本上都是使用@Autowired这个注解,用来注入已有的bean.但是有些时候,会注入失败.当我们加上参数(required=false)就能解决.今天整 ...