Tomcat-maxHttpHeaderSize导致的内存溢出

现象:

`生产环境运行一段时间后总是出现内存溢出,导致服务自动宕机。根据反馈,系统在执行某一任务时就会出现该现象,通过本地进行测试,很快也复现了该问题。

原因分析:

通过java自带工具jconsole监控服务,发现内存占用一直居高不下,老年代堆空间始终得不到回收。

Alt

通过jvisualvm工具导出dump日志,再使用jvisualvm进行分析。可以看到byte数组占据了93%的堆内存空间。

在这里插入图片描述

转到实例视图,查看具体的实例

在这里插入图片描述

看到持有这个byte数组对象的是一个 HeapByteBuffer对象,HeapByteBuffer是java NIO中的对象。程序中没有使用NIO,推测NIO应该在Tomcat中被使用。然后查看Tomcat相关配置,发现有一项配置是max-http-header-size=1024000(10M),这是设置请求头大小,默认大小为8KB。如果设置了max-http-header-size参数,会覆盖掉原有的默认值。

在这里插入图片描述

为什么会有那么大的数组对象

从Http11InputBuffer初始化过程可以看到,maxHeaderBufferSize会作为参数传递给headerBufferSize。

在这里插入图片描述
看到

继续跟踪发现headerBufferSize会被用于分配缓冲大小。通过Http11InputBuffer可以看出,若是max-http-header-size配置为10M,Http11InputBuffer就会分配一个10M的缓冲区,同理,Http11OutputBuffer也会分配10M的缓冲区,那么一个请求线程就是20M。
在这里插入图片描述

流程分析

Tomcat 接收请求时

  1. NioEndpoint 将请求封装为 NioEndpoint$SocketProcessor 交给 Tomcat ThreadPoolExecutor 执行处理
  2. 执行调用 AbstractProtocol$ConnectionHandler 的 process 方法
  3. 内部使用 HTTP11NioProtocol 处理此请求,会实例化一个 Http11Processor ,最终调用其 process 方法处理
  4. 在 Http11Processor 实例化时会直接初始化一个 10M大小的 Http11OutputBuffer和 一个10M大小的Http11InputBuffer
  5. 平均每个线程持有 20M 大小的缓存数组,当并发请求时,线程池里的线程数达到一定数量时,超出了设置最大堆内存就会导致 OOM
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值