Ivan-yy

导航

记录一次开发过程中Tomcat buffer OOM的问题

起因:
项目是基本spring cloud开发,网关zuul,注册中心eureka,rpc feign,由于要测试一次主流程的调用,所以在本地将所有的服务全部启动了,每个服务分配堆内存1g.
主流程业务逻辑在网关,大体流程就是: 先调app服务校验,取值,再调acq服务采集数据,acq服务中会调用persist持久化数据.在发起一次请求时在访问acq服务时,acq服务出现OOM,报错截图如下:
解决思路:
看到报错信息,是tomcat接收请求时 buffer init失败,然后出现OOM.那么此时OOM的原因可能是以下几种情况:
1.tomcat在初始化一个请求缓冲池时,分配了一个很大的对象,导致堆中无法分配,最后出现OOM
2.网关调用时feign的配置有问题
带着上述猜想,首先复现一遍问题,同时使用jstat监控jvm情况.命令 jstat -gcutil 1000 表示监控进程号pid的java进程jvm堆中各项指标及gc次数,每隔1000ms打印一次

发现在请求的瞬间进行了两次young gc, 两次full gc.猜想大概率就是分配了大对象导致jvm堆中无法分配该对象
先回顾一下jvm堆分配对象的流程:首先新对象都会分配在新生代eden中,当eden内存不够时会触发young gc,将gc后存活的对象放入s0或者s1区中,此时如果eden区内存还不够分配新对象,新对象就会通过担保机制进入到老年代oden中,老年代如果空间不够会触发full gc, 此时还不够的话就会OOM.
首先监控显示第一次young gc后eden区存活对象全部复制到了s1区中,第二次 young gc时 s0,s1,eden区大部分对象都被回收,而老年代中在进行了两次full gc后使用率并未下降.
再通过分析OOM时产生的dump文件(使用java自带的jvisualvm),发现占用内存较大的对象是很多char[]对象.
根据分析和猜想,应该是请求过来时tomcat分配一个大对象,然后导致了OOM,最后在配置文件中发现了两行配置:
server.tomcat.max-http-header-size=1024000000
server.tomcat.max-http-post-size=1024000000
size设置小一些的值后问题解决.

posted on 2020-11-22 15:23  Ivan-yy  阅读(235)  评论(0编辑  收藏  举报