一、常见溢出问题
1) java.lang.OutOfMemoryError:PermGen space
永久带溢出
优化:通过MaxPermSize参数设置PermGen space大小;
2) java.lang.OutOfMemoryError:java heap space
堆内存溢出
优化:-Xmn(最小值)–Xms(初始值) -Xmx(最大值),手动设置 Heap(堆)的大小;
3) java.lang.StackOverFlowError:栈溢出
栈溢出
优化:通过Xss参数调整;
二、堆栈是什么
1、堆
1)数据存储(new对象、数组放在堆里);
2)堆内存分为:年轻代和老年代,默认年轻代比老年代小,年轻代占3/8,老年代占5/8;
3)年轻代分为eden、存活区s0、存活区s1,比例为8:1:1;
2、栈
运行时单位(方法、定义的变量、常量放在栈里),可以把栈看做是java运行时的快照,瞬时的,并不是不变的
3、性能出现问题时该看堆还是栈?
1)CPU使用过高:方法导致,此时应该从栈中看
2)磁盘IO高:看栈
3)内存过高:看堆
4)GC:看堆
三、JVM内存分配机制
内存结构如下图,用红色圆圈来代替对象,圆圈上的线条表示对象的引用。
1、new对象直接进入Eden区,Eden区满后,应用程序暂停,Eden区开始进行ygc
* ygc,也称年轻代GC,GC过程中所有请求排队,响应时间变长
* ygc触发条件:只会在Eden区满了触发
* ygc执行操作:
1)判断Eden区对象是否有引用,然后标记
2)有引用的对象挪到存活取s0,没引用的对象回收掉
2、两个存活区大小相等,位置互换
* s0,s1大小相等,永远有一个存存活区为空
* Eden区再次满了之后,应用程序暂停运行,eden区开始进行ygc
* ygc执行操作:
1)寻根判断,判断Eden区、s0区对象是否有引用,然后标记
2)有引用的对象挪到存活取s1,没引用的对象回收掉
* Eden区再次满了之后,应用程序暂停运行,eden区开始进行ygc
* ygc执行操作:
1)寻根判断,判断eden区、s1区对象是否有引用,然后标记
2)有引用的对象挪到存活区s0,没引用的对象回收掉
3、什么样的对象进入老年代
1)大对象直接进入老年代(大对象大小可配置)
2)长期存活的对象进入老年代(默认age=15,一次ygc的周期age+1)
3)对象动态分配原则,ygc时计算
4)空间担保原则
4、对象动态分配
1)动态分配规则:
* 定义:相同age的对象的大小之和 大于1/2的存活区的大小,即sum(age.mem) >= (1/2)s0 ,则将>=age的对象挪到老年代。
* 计算规则:从小到大算,先从age1算,不满足再从age2计算
2)举例:存活区s0中放对象,s1中空着,so中对象如下
对象:a b c d e f g h k dw xw
Age: 1 2 3 4 2 3 3 2 5 6 9
若b.mem+e.mem+h.mem >= 1/2 s0 则把age>=2的对象 即b c d e f g h k dw xw都挪到老年代,此时s0中只剩下a。
3)什么时候进行对象动态分配:ygc时计算,解决存活区对象放不下问题。
5、空间担保原则
1)空间担保原则定义
每次ygc时预估这次ygc要往老年代放多少东西,如果要往老年代存放的对象大小大于老年代大小,则不进行ygc,改为进行full gc。
2)触发条件:ygc
3)fullgc操作
eden区、存活区、老年代、永久区都进行GC
* 寻根判断
* 回收,eden区挪到存活区,老年代中引用对象,继续保持
四、小结
1、ygc触发条件:
eden区满
2、full gc触发条件:
老年代满、空间担保原则生效时、永久带满、代码显示调用(system.gc(),getRuntime.gc())、执行jmap -dump
3、空间担保原则触发条件:
ygc
4、jvm最小大小和最大大小都设置一样目的:
为了避免申请销毁过程损耗性能---小了申请,大了销毁
5、ygc与full gc频率要求
每次ygc,时间不要超过100ms;fullgc,对次数有要求,有的要求1小时一次,有得要求12小时1次,最快也得半小时一次,不能再频繁了
6、为什么要就行分代收集
若果不进行分代收集,即没有存活区,则年轻代满后直接往老年代挪,老年代满后就full gc,这样会导致full gc频繁,full g耗时长,full gc期间程序暂停;如果只有一个存活区,full gc 频率也挺高,2个可以减少对象进入老年代的频率,从而减少full gc频率;
更多内容欢迎关注微信公众号查看