前因:
因为REST规范,定义资源获取接口使用GET请求,参数拼接在url上。
如果按上述定义,当参数过长,超过tomcat默认配置 max-http-header-size :8kb
会报一下错误信息:
Request header is too large
可以修改springboot配置,调整请求头大小
server: max-http-header-size: xxx
后果:
如果max-http-header-size设置过大,会导致接口吞吐下降,jvm oom,内存泄漏。
因为tomcat 会用HeapByteBuffer 预分配请求头内存大小,在堆上分配。
请求和响应都是一样的配置,每次请求处理预先分配,2倍配置值内存大小在 jvm 堆中
请求过多,导致线上内存暴涨,老年代有3GB多。使用jmap dump线上内存数据,使用 JProfiler 分析。
符合配置大小和源码对象
数组有3GB,和老年代和eden区总和大小相近。
-XX:PretenureSizeThreshold jvm参数用来设置默认值,当数组或对象大小超过这个设定值,直接在 Old Gen 老年代分配;默认值0,当超过eden区的大小的时候,直接分配到old区。
使用 java -XX:+PrintCommandLineFlags -version
发现并没有使用
-XX:PretenureSizeThreshold参数,所以是
max-http-header-size设置过大,eden区分配不够,直接分配到old区,堆区内存不够,自动扩容,导致old区数据越来越多,频繁触发FullGC。
JVM初始分配的内存由-Xms指定,默认是物理内存的1/64;JVM最大分配的内存由-Xmx指定,默认是物理内存的1/4。默认空余堆内存小 于40%时,JVM就会增大堆直到-Xmx的最大限制;空余堆内存大于70%时,JVM会减少堆直到-Xms本文来源gaodai$ma#com搞$代*码6网的最小限制。因此服务器一般设置-Xms、 -Xmx相等以避免在每次GC后调整堆的大小。
其中http-nio-9005-exec-线程有146个,和前面配置需要分配的20M内存请求,相乘的数据与3000MB相近。