-
2021-01-17 15:18:15
OOM问题排查思路与指令
实际生产项目中,不可避免的会遇到服务器内存不足引发告警的问题,很多时候可能就是因为部署的服务占用了太多的内存导致的。
当然,我们可以通过设置java的内存参数来控制内存的最大占用量,但是JVM内存不足了也是一个很头疼的问题。
如果服务部署的时候,允许外部内存检查等VM之类的工具远程连接还好,但是很多公司出于性能等种种原因,并不会开放远程连接的功能。
这样的话,就只能通过指令来定位问题了!
常用指令:
1.top指令:
类似windows环境的任务管理器,可以看到各个进程的使用情况。然后ctrl+m进行排序,找出内存消耗最高的几个进程。
根据pid,查询性能消耗比较高的是什么服务在运行l
ps -ef|grep 26810
2.jstat :虚拟机统计信息监视工具
jstat是用于监视虚拟机各种运行状态信息的命令行工具。可以显示进程中的类加载、内存、垃圾收集、即时编译等运行数据
常用到的如下:
1.jstat -gc *** 间隔时间 输出条数 (监视java堆状况,包括Eden区、2个Survivor区,老年代、永久代等的容量,已用空间,垃圾收集时间合计等信息)
2.jstat -gcutil *** (监视内容与-gc类似,但输出主要关注已使用空间占用总空间的百分比)
3.jmap : java内存映射工具
jmap (Memory Map for Java) 命令用于生成堆转储快照(一般称为:heapdump或dump文件)
更多相关内容 -
一次OOM问题排查过程实战记录
2021-01-05 06:50:24上周运维反馈线上程序出现了OOM,程序日志中的输出为 Exception in thread http-nio-8080-exec-1027 java.lang.OutOfMemoryError: Java heap space Exception in thread ... -
线上OOM问题排查
2021-11-10 13:06:25这段时间公司在搞活动,系统的订单量比平时增加了好几倍,活动开始的第一天下午,业务反馈说系统崩溃了,然后开始排查原因,发现服务并没有挂,只是响应速度异常慢。查看了cpu和内存,发现cpu是正常的,内存也是够用...这段时间公司在搞活动,系统的订单量比平时增加了好几倍,活动开始的第一天下午,业务反馈说系统崩溃了,然后开始排查原因,发现服务并没有挂,只是响应速度异常慢。查看了cpu和内存,发现cpu是正常的,内存也是够用的,说明机器的cpu和内存都没有问题。
top #查看cpu和内存的使用情况
然后查看这个服务的堆使用情况,发现老年代已经满了,在频繁fullGC,并且每次fullGC回收的内存都很少。于是找运维重启了服务,重启后服务恢复正常了,先解决问题再找原因。通过监控堆栈的使用情况,发现老年代增长速度很快,如下图,但是每次老年代回收极少,考虑可能存在内存泄漏,服务启动一次只能勉强撑1个小时,然后找运维把堆扩大到(3G),然后设置定时重启,每三个小时自动重启服务,让服务基本保持正常,然后继续抓紧排查问题。
jps #查看Java进程及pid jstat -gcutil pid 1000 #1000表示时间间隔
S0C:第一个幸存区的大小 S1C:第二个幸存区的大小 S0U:第一个幸存区的使用大小 S1U:第二个幸存区的使用大小 EC:伊甸园区的大小 EU:伊甸园区的使用大小 OC:老年代大小 OU:老年代使用大小 MC:方法区大小 MU:方法区使用大小 CCSC:压缩类空间大小 CCSU:压缩类空间使用大小 YGC:年轻代垃圾回收次数 YGCT:年轻代垃圾回收消耗时间 FGC:老年代垃圾回收次数 FGCT:老年代垃圾回收消耗时间 GCT:垃圾回收消耗总时间
开始想办法排查内存泄漏问题,使用jmap查看占用内存最大的对象,结果不太理想,只看到char,string还有hashmap占用了大量内存。最开始走了些弯路,怀疑代码中是不是hashmap有内存泄漏了,结果找了半天没有找到可疑的地方。
jmap -histo 1 | head -20 #查看占用内存最大的前20个对象
那只能把堆dump出来在本地分析,毕竟线上服务不能停,考虑怎么安全地把堆dump出来,想到了用jmap或者是arthas。jmap -dump有个问题,这个命令执行,JVM会将整个heap的信息dump写入到一个文件,heap如果比较大的话,就会导致这个过程比较耗时,并且执行的过程中为了保证dump的信息是可靠的,所以会暂停应用。所以jmap被pass了,于是找运维安装了arthas。
arthas下载地址:curl -O https://arthas.aliyun.com/arthas-boot.jar
#启动arthas java -jar arthas-boot.jar #提示选择进程,输入编号选择对应的进程
dashboard #查看仪表板
headdump #dump堆栈信息,速度很快,900多M的堆几秒钟就dump完了
然后把dump文件下载到本地,开始分析dump文件,分析dump文件常用的工具有jdk自带的jvisualvm,eclipse的MAT,我开始是用jvisualvm分析,效果不理想,可以看到Integer,HashMap占用内存很大,但是也说明不了问题,如下图,后来改用MAT分析,发现这个功能很好用,推荐用MAT分析堆栈
使用MAT分析如下,发现org.hibernate.internal.SessionFactoryImpl占用了大量内存,进一步展开这个类,发现是queryCacheplan占用了很多内存,最终在queryCacheplan中找到了罪魁祸首,代码里面写了in查询,结果这个in查询的条件有800多,类似这样的sql还有很多,难怪内存会不断增长,sql语句如下:
select distinct xxxEntity1 from xxxEntity1 xxxEntity1 inner join xxxEntity2 xxxEntity2 with xxxEntity1.deliveryNo = xxxEntity2.order_No where xxxEntity.type = ?1 and xxxEntity1.caseNo in (?2, ?3, ?4, ?5, ........ ?864, ?865, ?866)
然后找到代码中这个sql语句,优化后重新上线,问题解决了,已经跑了很多天一直很正常。
QueryPlanCache 内存泄漏解决方法
产生的原因: hibernate中的QueryPlanCache会缓存sql,以便于后边的相同的sql重复编译。如果in后的参数不同,hibernate会把其当成不同的sql进行缓存,从而缓存大量的sql导致heap内存溢出。
解决方法: 通过设置缓存最大值来进行限制,不设置默认是2G。
spring:
jpa:
properties:
hibernate:
query:
plan_cache_max_size: 64
plan_parameter_metadata_max_size: 32
plan_cache_max_soft_references: 1024
plan_cache_max_strong_references: 64 -
一次线上OOM问题排查
2019-08-05 21:29:22二、问题排查 1、出现OOM问题了,脑袋里第一反应就是项目中出现内存泄露或者内存溢出了。先登录ELK,根据关键词 “java.lang.OutOfMemoryError” 进行搜索,果然发现有OOM错误日志。 org.springframework.scheduling...一、短信预警
某天下午风和日丽,下午五点钟早早的就发版上线。七点准备下班的时候突然收到短信预警,项目OOM了,wtf !!!二、问题排查
1、出现OOM问题了,脑袋里第一反应就是项目中出现内存泄露或者内存溢出了。先登录ELK,根据关键词 “java.lang.OutOfMemoryError” 进行搜索,果然发现有OOM错误日志。org.springframework.scheduling.quartz.JobMethodInvocationFailedException: Invocation of method 'run' on target class [class com.kingdee.finance.data.credit.ydreport.task.YdReportAppendixInfoTask] failed; nested exception is java.lang.OutOfMemoryError: Java heap space at org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean$MethodInvokingJob.executeInternal(MethodInvokingJobDetailFactoryBean.java:266) at org.springframework.scheduling.quartz.QuartzJobBean.execute(QuartzJobBean.java:75) at org.quartz.core.JobRunShell.run(JobRunShell.java:213) at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:557) Caused by: java.lang.OutOfMemoryError: Java heap space at java.util.Arrays.copyOf(Arrays.java:3332) at java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:137) at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:121) at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:622) at java.lang.StringBuffer.append(StringBuffer.java:383) at java.net.URLEncoder.encode(URLEncoder.java:271) at com.longsec.http.HttpConnection.httpPostWithJSON(HttpConnection.java:548) at com.kingdee.finance.data.credit.ydreport.service.impl.YdCreditAppendixInfoHandler.sendRequest(YdCreditAppendixInfoHandler.java:151) at com.kingdee.finance.data.credit.ydreport.service.impl.YdCreditAppendixInfoHandler.handleAppendixRequest(YdCreditAppendixInfoHandler.java:46) at com.kingdee.finance.data.credit.ydreport.service.impl.YdCreditAppendixInfoHandler$$FastClassBySpringCGLIB$$a4a2cc16.invoke(<generated>) at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:736) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:671) at com.kingdee.finance.data.credit.ydreport.service.impl.YdCreditAppendixInfoHandler$$EnhancerBySpringCGLIB$$e0cc861a.handleAppendixRequest(<generated>) at com.kingdee.finance.data.credit.ydreport.task.YdReportAppendixInfoTask.handleAppendixInfoTask(YdReportAppendixInfoTask.java:56) at com.kingdee.finance.data.credit.ydreport.task.YdReportAppendixInfoTask.run(YdReportAppendixInfoTask.java:43) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:497) at org.springframework.util.MethodInvoker.invoke(MethodInvoker.java:265) at org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean$MethodInvokingJob.executeInternal(MethodInvokingJobDetailFactoryBean.java:257) ... 3 more
2、根据OOM堆栈错误日志,去扫了一眼代码并未看出什么问题。既然代码没有明显的内存泄露迹象,只能把目光转向堆内存对象分析了。
3、从服务器上导出堆内存溢出的dump文件,用mat 打开分析一波。
可以看到一个StringBuffer占了400M,另一个String对象占了224M,堆内存溢出跟这两个对象脱不了干系。搜索了下代码发现项目中出现问题的地方并没有用到StringBuffer这个类,应该是某个jar里有引用到的。点击String对象,看看value。
4、根据String 对象的值,推测这是一个json格式的参数。用“username”和“businessNumber” 在代码中搜索。
这段代码就是组装请求参数,上面224M的String对象就是由这段代码产生。但出现400M的StringBuffer对象才是导致OOM的元凶,需要继续追查。
整理出代码的调用关系,packRequestJson —> sendRequest —> HttpConnection.httpPostWithJSON —> URLEncoder.encode。很显然StringBuffer对象是由jar包中的URLEncoder.encode 方法中产生,这也跟日志中的堆栈日志正好也能对应上。
三、问题原因
根据上面分析以及查看代码,得知定时任务一次拉取 300条记录批次处理,组装参数得到一个224M 大小的String对象,然后在HTTP请求发送之前经过 URLEncoder.encode 方法 产生了一个400M大小的StringBuffer,直接导致了“java.lang.OutOfMemoryError” 异常。四、解决方案
400M的大对象是由于一次取出300条记录,参数拼接生成的。可以将批处理记录数调小一点,就可以解决问题,批处理记录数应从数据配置中获取。四、总结
1、线上异常预警,首先要查看项目日志。根据错误日志,来判断问题出现原因。确定好问题排查方向再选择相应的工具进行分析,多角度的观察,抽丝剥茧,直到找到问题的根源。2、问题排查要熟悉Java应用排查问题常用工具,比如:jstack、jmap、jps。
查看某个应用的进程id以及启动参数:jps -v | grep “xxx”
dump堆内存:jmap -dump:live,format=b,file=/heapdump.hprof {pid}
导出线程栈:jstack {pid} > /jstack.txt -
记一次线上OOM 问题排查过程!
2019-09-08 11:00:00公众号后台回复“学习”,获取作者独家秘制精品资料扫描下方海报二维码,试听课程:上周运维反馈线上程序出现了OOM,程序日志中的输出为Exception inthread ...公众号后台回复“学习”,获取作者独家秘制精品资料
扫描下方海报二维码,试听课程:
上周运维反馈线上程序出现了OOM,程序日志中的输出为
Exception in thread "http-nio-8080-exec-1027" java.lang.OutOfMemoryError: Java heap space Exception in thread "http-nio-8080-exec-1031" java.lang.OutOfMemoryError: Java heap space
看线程名称应该是tomcat的nio工作线程,线程在处理程序的时候因为无法在堆中分配更多内存出现了OOM
幸好JVM启动参数配置了-XX:+HeapDumpOnOutOfMemoryError,使用MAT打开拿到的hprof文件进行分析。
第一步就是打开Histogram看看占用内存最大的是什么对象:
可以看到byte数组占用了接近JVM配置的最大堆的大小也就是8GB,显然这是OOM的原因。
第二步看一下究竟是哪些byte数组,数组是啥内容:
可以看到很明显这和HTTP请求相关,一个数组大概是10M的大小。
第三步通过查看GC根查看谁持有了数组的引用:
这符合之前的猜测,是tomcat的线程在处理过程中分配了10M的buffer在堆上。
至此,马上可以想到一定是什么参数设置的不合理导致了这种情况,一般而言tomcat不可能为每一个请求分配如此大的buffer。
第四步就是检查代码里是否有tomcat或服务器相关配置,看到有这么一个配置:
至此,基本已经确定了八九不离十就是这个不合理的最大http请求头参数导致的问题。
到这里还有3个疑问:
即使一个请求分配10M内存,堆有8GB,难道当时有这么多并发吗?800个tomcat线程?
参数只是设置了最大请求头10M,为什么tomcat就会一次性分配这么大的buffer呢?
为什么会有如此多的tomcat线程?感觉程序没这么多并发。
先来看问题1,这个可以通过MAT在dump中继续寻找答案。
可以打开线程视图,搜索一下tomcat的工作线程,发现线程数量的确很多有401个,但是也只是800的一半:
再回到那些大数组的清单,按照堆分配大小排序,往下看:
可以发现除了有10008192字节的数组还有10000000字节的数组,查看引用路径可以看到这个正好是10M的数组是output buffer,区别于之前看到的input buffer:
好吧,这就对了,一个线程分配了输入输出两个buffer,占用20M内存,一共401个线程,占用8GB,所以OOM了。还引申出一个问题:为啥有这么多工作线程!
再来看看问题2,这就需要来找一下源码了,首先max-http-header-size是springboot定义的参数,查看springboot代码,可以看到这个参数对于tomcat设置的是MaxHttpHeaderSize:
然后来看看tomcat源码:
进一步看一下input buffer:
buffer大小是MaxHttpHeaderSize+ReadBuffer大小,后者默认是8192字节:
<attribute name="socket.appReadBufSize" required="false"> <p>(int)Each connection that is opened up in Tomcat get associated with a read ByteBuffer. This attribute controls the size of this buffer. By default this read buffer is sized at <code>8192</code> bytes. For lower concurrency, you can increase this to buffer more data. For an extreme amount of keep alive connections, decrease this number or increase your heap size.</p> </attribute>
这也就是为什么之前看到大量的buffer是10008192字节的。显然还有一批内容是空的10000000字节的buffer应该是output buffer
来看看源码:
这是一个header buffer,所以正好是10000000字节。
至于问题3,显然我们的应用程序是配置过最大线程的(查看配置后发现的确,我们配置为了2000,好吧有点大),否则也不会有401个工作线程(默认150)
如果当时并发并不大的话就一种可能,请求很慢,虽然并发不大,但是因为请求执行的慢就需要更多线程,比如TPS是100,但是平均RT是4s的话,就是400线程了。
这个问题的答案还是可以通过MAT去找,随便看几个线程可以发现很多线程都在等待一个外部服务的返回,这说明外部服务比较慢
然后去搜索当时的程序日志,可以发现有很多"feign.RetryableException: Read timed out executing的日志"。。。追杀下游去!慢点,我们的feign的timeout也需要再去设置一下,别被外部服务拖死了。
END
如有收获,请划至底部,点击“在看”,谢谢!
欢迎长按下图关注公众号石杉的架构笔记
BAT架构经验倾囊相授
-
Redis OOM问题排查
2019-11-16 11:50:02看到Redis报了OOM的错误,而且服务响应速度非常慢,页面上丢了很多数据,赶紧起来查看问题。 2. 问题排查 我们的系统架构是双边双活的,两个DC(Primary和GSB)都会有数据写进来,通过API把数据存到数据库(双边... -
线上服务OOM问题排查
2020-10-29 18:13:21问题描述 node2 服务异常,日志报错: java.lang.OutOfMemoryError: Java heap space (对外风控服务正常,因为node1服务正常,负载均衡服务会自动剔除异常节点) 排查过程 由于 JVM的启动参数没有显示指定..... -
容器OOM问题排查思路
2018-11-26 21:52:19序言 又是一个冬季,在这寒冷的冬季,总是让人心动。。。迷雾之城 外界的刁难,挑战。。。其实并不是最难的,最难的总是内部难以安抚,OOM。。。内存泄漏,OOM ... -
一次OOM问题排查
2018-01-18 17:39:16问题描述 用户问题:用户发现自己...经过我们的排查,发现cpu的两次间歇飙高是由于客户系统当时发生了OOM(out of memory)的情况,并触发了oom-killer造成的。但客户并不接受这个结论,认为是云服务器的异常导致了c... -
Java线上环境OOM问题排查
2022-03-03 21:53:50常见的问题排查方式 查看服务的进程是否存在 ps -ef | grep 服务名 ps -aux | grep 服务名 查看服务的日志 cat -n xxx_log |grep "OutOfMemoryError" java.lang.OutOfMemoryError GC overhead limit exceeded ... -
OOM问题排查及原因解析
2019-11-06 16:31:11现在才意识到,该机器是跑mq脚本的固定机器,由于进程开的太多导致内存占用太大,导致内存不够从而发生OOM kill问题。 二、深入理解OOM 2.1 Linux OverCommit Linux下允许程序申请比系统可用内存更多的内存... -
OOM问题排查中Jstat,jstack,jmap和MAT等工具的使用
2020-08-12 16:26:41出现OOM问题后, 我们如何排查问题的出现点呢? 在这篇博客中我只是简单的说下如何排查问题的。 找到问题进程ID 第一步都是确定你的服务的进程id,有两种linux指令使用, top命令 使用top -c 会列出当前的进程列表: ... -
linux内存泄漏与OOM问题排查
2021-05-12 03:33:28$ top #或ps $ pmap 上面3步可以用工具bcc包中的memleak分析 $ memleak -a -p $(pidof app) #已知进程号情况下,或者直接 $memleak -a 2、内存泄露最终通过OOM释放 #查看OOM的进程 $ grep "Out of memory" /var/log/... -
Java OOM 问题排查
2020-12-18 14:23:38去代码中查看此处代码问题 二、可以使用 1、IBM heapAnalyzer 分析内存泄露的原因 下载地址:https://www.ibm.com/support/pages/ibm-heapanalyzer 桌面上创建一个.bat文件,文本内容为,定位到jar的目录地址 cd C... -
OOM问题排查
2019-10-10 17:46:19监控工具jvisualvm使用: jdk/bin 运行jvisualvm ps aux |more 详细信息包含cpu,内存 ps -mp pid -o THREAD,tid,time | sort -k2r 查看指定进程中各个线程占用CPU的状态,选出耗时最多、最繁忙的线程id ... -
java OOM问题排查
2014-11-14 18:05:36在做服务器端开发的时候,经常会遇到服务由于内存溢出挂掉的情况,这种情况的发生一般来说是很难预期的,也比较难以重现,对于这种问题,一般可以通过记录内存溢出时候的堆信息来排查。 1、首先可以查看服务器... -
OOM的排查思路
2021-05-19 17:35:09什么是OOM 简单来说,就是程序的内存不够了,挂掉了 OOM的原因 oom的原因其实就一个,内存不够了,我们要细分的就是哪里的内存不够了,以及为什么内存不够了 栈溢出 这种情况属实比较少,一般就是栈调用太深了,比如... -
Java OOM问题如何排查
2021-11-08 17:22:24Java OOM问题如何排查 - 南山饱虎 - 博客园 -
记一次OOM问题排查过程
2021-03-17 14:54:13记一次OOM问题排查过程发布时间:2019-05-01 20:05,浏览次数:459, 标签:OOM上周运维反馈线上程序出现了OOM,程序日志中的输出为Exception in thread ... -
jvm性能调优实战 -57数据日志分析系统的OOM问题排查
2021-04-28 23:12:28文章目录PreCase初步分析内存快照功夫在诗外:问题在JVM参数上分析一下JVM的GC日志分析一下JVM运行时内存使用模型优化第一步:增加堆内存大小优化第二步:改写代码总结 Pre 今天的案例背景是一个每天10亿数据量的... -
一次生产OOM问题排查
2020-05-23 17:48:39我们有一个生产服务,规模是12台机器*6个节点 = 72个节点的服务,最近老是出现某个节点突然挂掉的情况,问题出现频繁,一天需要重启很多个节点 查看tomcat日志,发现是堆内存溢出 使用jmap -heap pid查看各个JVM内存... -
linux下OOM问题排查 互联网技术圈 互联网技术圈
2021-05-11 17:27:46经过我们的排查,发现cpu的两次间歇飙高是由于客户系统当时发生了OOM(out of memory)的情况,并触发了oom-killer造成的。但客户并不接受这个结论,认为是云服务器的异常导致了cpu飙高,而cpu的升高又导致了oom情况的...