记一次OOM查询处理过程

记一次OOM查询处理过程

  • 问题的爆出及分析排查现场

  • 排查后的解决方案

  • 项目的jvm参数

  • 总结

一、问题的爆出及分析排查现场

  服务偶尔会出现不可用的情况,导致出现time out,然后我迅速登录现场,直接查看当时的gc日志,不废话,直接上图

通过这个图可以发现在10点7分、8分的时候频繁Full GC,但是GC之后 年轻代,老年代并没有少。并且Full GC时长5s8多,造成stop-the-world5s8,因此应用程序会出现无影响。再贴一张图

通过这个可以看到内存慢慢的通过GC降下来了

根据这些信息基本可以断定,是由于什么操作导致内存飙升,并且都是一些大对象,就是由于这些大对象导致年轻代放不下,因此直接进入老年代(分配担保策略),而这个操作占用的内存大,因此触发了Full GC(jvm 触发Full GC的情况 https://blog.csdn.net/chenleixing/article/details/46706039/ ),再加上又比较耗时,因此频繁Full GC,因为对象一直被强引用着,导致无法被清除.

接下来立马使用jdk 自带的工具 jmap进行dump,然后使用jdk自带的jvisualvm进行dump文件分析,分析图如下:

通过这个图可以看到Xobj相关的对象大小占到内存的61%左右,由于我对于这个项目又比较熟悉,所以很快就能定位是由于操作Excel文件导致的.因为一看这个就知道是和xml解析相关的

当然也可以通过分析工具来定位到比较具体的点的信息。

当定位是和Excel相关时,紧接着看了下和excel相关的处理文件,发现文件都不大,最大的也就40万左右,7M而已,那么为什么会产生这么大的内存对象内,于是乎,就去百度,然后得到的结果大概是poi读取excel有两种模式,一种user model 另一种event mode, 而我使用的是user model 模式,这种模式使用的内存和cpu 较之 event model都要大很多。而我为了方便,又是将excel 文件全部读取然后进行处理。

二、排查后的解决方案

   解决方案分两步走,一步是代码层面、一步是jvm参数方面

    代码层面:读取excel文件使用event model 方式,并且每读取100行,便处理然后释放引用,这样便于被GC回收

 jvm参数方面:之前年轻代是300M左右,而堆的总内存大小是4G,感觉年轻代的设置不太合理,因此调到800M,然后进行观察,观察后可进行适当的调整

三、项目的jvm参数

-XX:CICompilerCount=3 	设置编译线程的数量。JVM在server模式下默认是2,在client模式下默认是1。如果使用分层编译的话,这个值会扩展到与CPU核数一样的值。
-XX:InitialHeapSize=4294967296 	设置堆的初始值
-XX:InitialTenuringThreshold=5  设置初始的对象在新生代中最大存活次数
-XX:MaxHeapSize=4294967296 	设置堆分配的最大值,单位字节
-XX:MaxNewSize=348913664 	新生代占整个堆内存的最大值。从Java1.4开始, MaxNewSize成为 NewRatio的一个函数
-XX:MinHeapDeltaBytes=196608 

-XX:OldPLABSize=16
-XX:OldSize=3946053632 

-XX:+UseCompressedOops  可以压缩指针,起到节约内存占用的新参数。使用compressed pointers。这个参数默认在64bit的环境下默认启动,但是如果JVM的内存达到32G后,这个参数就会默认为不启动,因为32G内存后,压缩就没有多大必要了,要管理那么大的内存指针也需要很大的宽度了
-XX:SurvivorRatio=8  Eden与Survivor的占用比例。例如8表示,一个survivor区占用 1/8 的Eden内存,即1/10的新生代内存,为什么不是1/9? 因为我们的新生代有2个survivor,即S1和S22。所以survivor总共是占用新生代内存的 2/10,Eden与新生代的占比则为 8/10。
-XX:MaxMetaspaceSize=512M  这个参数用于限制Metaspace增长的上限,防止因为某些情况导致Metaspace无限的使用本地内存,影响到其他程序。在本机上该参数的默认值为4294967295B(大约4096MB)
-XX:+UseCompressedClassPointers
-XX:CompressedClassSpaceSize=512M  的调优只有当-XX:+UseCompressedClassPointers开启了才有效
-XX:MaxTenuringThreshold=5	设置对象在新生代中最大的存活次数,最大值15,并行回收机制默认为15,CMS默认为4

-------------------CMS相关参数-------------------
-XX:CMSInitiatingOccupancyFraction=70  使用cms作为垃圾回收使用70%后开始CMS收集

-------------------收集器设置-------------------
-XX:+UseConcMarkSweepGC
	指 定在 Old Generation 使用 concurrent cmark sweep gc,gc thread 和 app thread 并行 ( 在 init-mark 和 remark 时 pause app thread). app pause 时间较短 , 适合交互性强的系统 , 如 web server
-XX:+UseParNewGC
	设置年轻代为并行收集。可与CMS收集同时使用。JDK5.0以上,JVM会根据系统配置自行设置,所以无需再设置此值。
-------------------堆设置-------------------
-Xms4096m
	指定 jvm 的最小 heap 大小 , 如 :-Xms=4g , 高并发应用, 建议和-Xmx一样, 防止因为内存收缩/突然增大带来的性能影响。
-Xmx4096m
	指定 jvm 的最大 heap 大小
-XX:NewSize=348913664
	设置年轻代大小
-XX:SurvivorRatio=8
	指 定 New Generation 中 Eden Space 与一个 Survivor Space 的 heap size 比例 ,-XX:SurvivorRatio=8, 那么在总共 New Generation 为 10m 的情况下 ,Eden Space 为 8m 

-------------------垃圾回收统计信息-------------------
-XX:+PrintGC
	输出形式:[GC 118250K->113543K(130112K), 0.0094143 secs]
			  [Full GC 121376K->10414K(130112K), 0.0650971 secs]
-XX:+PrintGCDateStamps
	GC发生的时间信息
-XX:+PrintGCDetails
	输出形式:[GC [DefNew: 8614K->781K(9088K), 0.0123035 secs] 118250K->113543K(130112K), 0.0124633 secs]
              [GC [DefNew: 8614K->8614K(9088K), 0.0000665 secs][Tenured: 112761K->10414K(121024K), 0.0433488 secs] 121376K->10414K(130112K), 0.0436268 secs]
-XX:+PrintGCTimeStamps
	输出形式:11.851: [GC 98328K->93620K(130112K), 0.0082960 secs]
-Xloggc:logs/gc.log.201808142235
	与上面几个配合使用,把相关日志信息记录到文件以便分析

-------------------3个设置滚动记录GC日志的参数  测试一下    -------------------
-XX:+UseGCLogFileRotation
	打开或关闭GC日志滚动记录功能,要求必须设置 -Xloggc参数
-XX:NumberOfGCLogFiles=1
	设置滚动日志文件的个数,必须大于1
	日志文件命名策略是,<filename>.0, <filename>.1, ..., <filename>.n-1,其中n是该参数的值
-XX:GCLogFileSize=512M
	设置滚动日志文件的大小,必须大于8k
	当前写日志文件大小超过该参数值时,日志将写入下一个文件

四、总结

  这个示例告诉我们,使用任何第三方jar,都需要进行严格的测试,确保不会对现有的系统造成伤害。开发人员需要对jvm进行了解,特别是GC这块,因为你new 的每一行代码都是和GC相关的,至少密不可分,知道的越多,了解的越清楚,才能保证写出好的 code ,有些坑不一定要踩

原文地址:https://www.cnblogs.com/Shock-W/p/9534860.html

时间: 2024-10-14 12:21:18

记一次OOM查询处理过程的相关文章

记一个程序oom的排查过程

一,背景 收到应用服务报警,然后登录上服务器查看原因,发现进程不再了. 二,问题分析 1,那么判断进程被干掉的原因如下: (1),机器重启了 通过uptime看机器并未重启 (2),程序有bug自动退出了 通过查询程序的error log,并未发现异常 (3),被别人干掉了 由于程序比较消耗内存,故猜想是不是oom了,被系统给干掉了.所以查messages日志,发现的确是oom了: Jul 27 13:29:54 kernel: Out of memory: Kill process 17982

记一次数据库调优过程(IIS发过来SQLSERVER 的FETCH API_CURSOR语句是神马?)

记一次数据库调优过程(IIS发过来SQLSERVER 的FETCH API_CURSOR语句是神马?) 前几天帮客户优化一个数据库,那个数据库的大小是6G 这麽小的数据库按道理不会有太大的性能问题的,但是客户反应说CPU占用很高,经常达到80%~90% 我检查了任务管理器,确实是SQLSERVER占的CPU 而服务器的内存是16G内存,只占用了7G+ 客户的环境: Windows2008R2 SQLSERVER2005 SP3 64位 企业版 服务器内存:16G CPU:8核 RDS:阿里云主机

SQL查询执行过程

MYSQL查询执行过程 客户端向服务器发送请求 服务器查询缓存,缓存中命中则结束,将结果返回客户端(返回前会检查用户权限),否则继续下边步骤 服务器端进行SQL解析.预处理,再由优化器生成对应的执行计划 根据执行计划调用存储引擎的API执行查询 将结果返回客户端 一.查询缓存 如果一条SQL语句以select开头,MySQL服务器将会尝试先在缓存中查询.每个cache都是以SQL文本做为key的,所以如果SQL语句中大小写不同也无法命中. 设置:my.cnf(Linuxe)/my.ini(Win

SequoiaDB的查询执行过程

SequoiaDB的查询执行过程 继续读了SDB的代码,重点还是内核的代码.从客户端–查询优化-查询执行的过程来描述一下查询的过程.希望可以搞清楚2个问题: SDB能做什么查询? 搞清楚SDB是怎么做查询的? 第一个问题的答案是: 理论上,SDB能做mongoDB能做的所有查询,SDB还支持SQL(我指的是SDB内建的支持,不是通过PG支持的查询) 实际上,我没有一个一个去测,SDB看起来mongoDB类的查询基本上完成了:SQL的支持还更像一个玩具.至于说我怎么得到这个结论的,请看下面的分析吧

记一次Elasticsearch OOM的优化过程——基于segments force merge 和 store type 转为 niofs

首选,说明笔者的机器环境(不结合环境谈解决方案都是耍流氓): cpu 32核,内存128G,非固态硬盘: RAID0 (4T * 6),单节点,数据量在700G到1800G,索引15亿~21亿.敖丙大人,在蘑菇街,集群分片,固态硬盘比不起. 转载请注明出处:https://www.cnblogs.com/NaughtyCat/p/elasticsearch-OOM-optimize-story.html  业务场景: 保存7天索引,每天有400G.发现ES时不时的OOM,和重启.当索引超过500

记一次内存泄露优化过程

背景 项目目前存在使用久了或者重复打开关闭某个页面,内存会一直飙升,居高不下,频繁发生GC.静置一段时间后,情况有所改善,但是问题依旧明显,如图1-1.1-2. 图1-1.操作时的内存使用情况 图1-2.静置时的内存使用情况 如上图1-1,是通过Android Studio查看内存(灰色)和CPU(红色)使用情况,可以看出内存有发生抖动并且是处于比较高的状态,再者,从logcat可以看到一直发生GC,如下图1-3: 图1-3. 出现这些情况,是有很多因素造成的,最主要的原因是发生了内存泄露:页面

面试题——分析从输入url到页面返回的过程(或者查询返回过程)

1. You enter a URL into the browser(输入一个url地址) 2.The browser looks up the IP address for the domain name(浏览器查找域名的ip地址) 导航的第一步是通过访问的域名找出其IP地址.DNS查找过程如下: 浏览器缓存 – 浏览器会缓存DNS记录一段时间. 有趣的是,操作系统没有告诉浏览器储存DNS记录的时间,这样不同浏览器会储存个自固定的一个时间(2分钟到30分钟不等). 系统缓存 – 如果在浏览器

记一次M1卡破解过程——weigr的第一次博文

一次偶然原因,在网上看到关于一些Mifare Classic card卡的破解文章,发现成本不是很高,并且门槛也不太高(本人笨得很,没觉得低)觉得很有意思,准备入坑一波.正好我寝室有饭卡.洗澡卡和直饮卡,为啥不试一试呢,嘿嘿.说干就干! 于是乎就在网上各种收集资料,(本人懒得很,不想去图书馆查资料)首先我们得搞懂M1卡的内部结构是吧,不然无从下手啊,所以我们先从结构说起吧. 可能文章有点长,着急的话可以直接跳过前面三个点 1.M1卡的存储内部结构: M1卡分为16个扇区,每个扇区对应4块(块0-

记一次PHP项目部署过程

首先介绍一下项目的基本情况:使用PHP语言开发,数据库用的是MySQL 5.5,HTTP服务器用的是Apache 2.2.早上十点到机房看了看服务器的基本情况:Windows 2000操作系统,没有安装Apache,没有php,幸好已经安装了MySQL数据库,替我省了点事.不过开心得有点太早了,机房老师告诉我她也不知道MySQL的登录密码.没有密码我的项目就没法连接数据库了,基本上等于废了.重装MySQL也没用,因为删除MySQL后原来的密码还是会保留在系统中,如果要修改密码,还是需要输入原来的