遇到一个问题,自己部署的线上springboot服务总是内存飙高,尤其是在30个以上的请求并发的时候,内存会立马大涨,并出现报错:
- m a" X5 q6 Njava.lang.OutOfMemoryError: Java heap space后来通过一步一步排查发现了导致这个问题的原因,就是当初在设置springboot的上传文件大小限制的时候加了一个配置:
! x. \1 o4 i( m) Pserver.maxHttpHeaderSize=102400000意思是http最大请求头大小设置成了大约100M,springboot默认的maxHttpHeaderSize是8K,如果没有特殊需要,应该是够用的。把这个配置注释掉就可以解决掉我提到的这个问题。! Y' g4 J& l% M, X
遇到跟我一样问题的小伙伴,可以检查一下是不是跟我犯了一样的错误,到这儿这个文章也可以结束了,但是鉴于这一次问题的排查过程走了很多“弯路”,不过却学到了很多东西,所以把我找原因,并且找到原因之后定位导致这个错误的具体是哪一行代码的过程记录一下,有兴趣的小伙伴可以看一下。
! d6 ?' H; ^9 {4 b会涉及到哪些知识点?
% U+ X5 l2 a4 d/ y! O; h& `* |
& h& N2 v* w* z* Z7 H接下来要讲的会涉及到一些知识点,不懂也没关系,我会简单说明:
: {, d3 [: @$ j- MJVM内存结构基础理解:2 G9 j! W; \0 B, _; C) Z2 w
% c. P8 z l& o* ujvm内存分成三块:堆内存(Heap Space)、方法区(Method Area/PermGen)和栈(Native Area)。. Y3 [$ O% a8 P! X
6 n/ Y0 ^4 G+ U/ |5 e5 i
堆内存:是内存大头,一般程序出现内存问题都在这里。由新生代和老生代组成。新生代由Eden空间、From Survivor空间、To Survivor空间组成。/ v5 J0 c( R8 d7 _2 E2 P
方法区:存储类信息、常量、静态变量等数据。又叫Non-Heap
2 _7 A d. w, n+ E. ]- T
栈:主要用于方法的执行
|" |8 u% T0 l: g% U. \; FJVM两种GC机制:3 Z5 s2 @/ |+ j
) \, n+ `% q. s3 @# B( f+ nGC是指java自动回收内存的机制,有两种方式:+ y6 q2 j9 ~5 A1 [5 }
/ X! l) t+ h/ V: x' ~
Minor GC:发生在新生代的垃圾收集动作。比较频繁,回收速度快。
5 U& F+ z& h5 n" E
Major GC/Full GC 是老年代GC(通常伴随Minor GC),速度很慢。! |. z! G- y) h* d4 `
因此要尽量避免触发Full GC., C0 \, V% p3 K1 b/ L+ ^JVM内存分配机制:4 T* m* p4 M; W5 b' T3 `
4 N6 B& e2 U% O简单介绍一下java中新建的对象,一般会放在新生代的Eden,经过Minor gc之后没有被销毁的对象会被复制到新生代的Survivor区域(至于为什么Survivor分为from to,这里涉及到一个复制算法,有兴趣的可以自行查阅)8 A0 G& c% I* M9 p( n/ V% S$ e
对象会被分配到老生代的几种情况:- T0 P3 A( A0 B. z* o
: s# C! _: U$ Z% Z
经历了默认15次minor gc之后,还没被销毁( i" r$ t3 H' J- c9 F" q: P
动态对象年龄判断) w/ L6 X/