一、问题情况

最近用户反映系统响应越来越慢,而且不是偶发性的慢。根据后台日志,可以看到系统已经有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问题分析与解决相关推荐

  1. 记一次线上OOM问题分析与解决,涨知识了!

    导读:以前写过几篇篇关于线上服务器cpu 100%了,该如何排查问题?一些粉丝私信说能不能结合案例来讲解.大好的周日被钉钉消息疯狂@,然后钉钉电话就开始轰炸,同事开发的一程序爆出内存溢出,压测环境居然 ...

  2. java mysql死锁_记一次线上mysql死锁分析(一)

    记录一次比较诡异的mysql死锁日志.系统运行几个月来,就在前几天发生了一次死锁,而且就只发生了一次死锁,整个排查过程耗时将近一天,最后感谢我们的DBA大神和老大一起分析找到原因. 诊断死锁 借助于我 ...

  3. 在线分析mysql死锁详解_记一次线上mysql死锁分析(一)

    记录一次比较诡异的mysql死锁日志.系统运行几个月来,就在前几天发生了一次死锁,而且就只发生了一次死锁,整个排查过程耗时将近一天,最后感谢我们的DBA大神和老大一起分析找到原因. 诊断死锁 借助于我 ...

  4. 记几次 [线上环境] Dubbo 线程池占满原因分析(第三次:GC STW)

    [线上环境] Dubbo 线程池占满原因排查系列 记几次 [线上环境] Dubbo 线程池占满原因分析(第一次:HttpClient) 记几次 [线上环境] Dubbo 线程池占满原因分析(第二次:C ...

  5. Probe:Android线上OOM问题定位组件

    配送骑手端App是骑手用于完成配送履约的应用,帮助骑手完成接单.到店.取货及送达,提供各种不同的运力服务,也是整个外卖闭环中的重要节点.由于配送业务的特性,骑手App对于应用稳定性的要求非常高,体现A ...

  6. 记一次线上coredump事故

    转自:http://www.likecs.com/show-16439.html 记一次线上coredump事故 1.事故背景 上周三凌晨,我负责的某个模块在多台机器上连续发生coredump,幸好发 ...

  7. 火山引擎MARS-APM Plus x 飞书 |降低线上OOM,提高App性能稳定性

    通过使用火山引擎MARS-APM Plus的memory graph功能,飞书研发团队有效分析定位问题线上case多达30例,线上OOM率降低到了0.8‰,降幅达到60%.大幅提升了用户体验,为飞书的 ...

  8. 线上服务器内存分析及问题排查

    转载自  线上服务器内存分析及问题排查 平常的工作中,在衡量服务器的性能时,经常会涉及到几个指标,load.cpu.mem.qps.rt等.每个指标都有其独特的意义,很多时候在线上出现问题时,往往会伴 ...

  9. 记一次线上环境 redis偶尔连接超时报错 解决

    记一次线上环境 redis偶尔连接超时报错 解决 贴出本地控制台日志 说实话,很痛苦,跟进很久了,一直认为的jvm程序所使用的配置的连接池框架问题 因为程序为 springboot 2 spring ...

最新文章

  1. Python基础——PyCharm版本——第九章、MySQL操作(核心4)
  2. [译] APT分析报告:09.伊朗APT34更新武器库——SideTwist变体
  3. linux怎么创建5个线程,简明Linux系统编程_5_创建线程(总第238期)
  4. Qt-捕获Windows消息
  5. 内嵌Tomcat的Connector对象的静态代码块
  6. 使用 Chrome 调试 Vue3 的 TypeScript 源码
  7. linux path_lookup,Linux虚拟文件系统(4)-- 路径名查找
  8. 烂泥:KVM虚拟机的关机与开启
  9. 桌面下雪软件测试工程师,Snow Flakes屏幕下雪动态屏保 模拟真实降雪情景的屏保程序...
  10. 基于SSM框架和easyUI框架的简易人事管理系统(六)
  11. SQL Server 2012 数据库可疑问题解决
  12. Winrm+python远程连接windows执行命令
  13. 如何通过阿里云APP进行域名备案?阿里云备案流程需要多久?
  14. HDR:Recovering High Dynamic Range Radiance Maps from Photographs
  15. JAVA领域10位大神
  16. Linux磁盘与目录的容量、连结档
  17. 通证经济大局观(三十):贵族的没落
  18. 软件设计师-操作系统知识
  19. Java的TCP/UDP网络编程+多线程实现服务器端与客户端间的通信
  20. Android之MediaPlayer(两种)基本使用方式

热门文章

  1. java求矩阵_java实现的n*n矩阵求值及求逆矩阵算法示例
  2. 工资管理系统-C++
  3. bash脚本运行C++程序
  4. Unity 计算图片真实存储大小(Preview视图)
  5. 文件透明加密,保护重要数据的安全性
  6. java插入排序(含插入排序代码)
  7. LINUX使用rm误删文件后恢复
  8. EPS首席执行官——荣获2021年安永年度企业家提名
  9. android11.0 12.0Launcher3修改某个app icon的图标
  10. TinyWS —— 一个C++写的简易WEB服务器(三)