跳到主要内容

16、JVM 调优实战 - 扩展知识点-面试题

1. 面试题:parnew+cms的gc,如何保证只做ygc,jvm参数如何配置

答:关键点是必须让Survivor区能放下所有存活对象,而且不能因为动态年龄判定规则直接升入老年代。然后只要Survivor区可以放下,那么下次Minor GC后还是存活那么多对象,依然可以在另外一块Survivor区放下,基本就不会有对象升入老年代里去。

参考方案:

  • 加大分代年龄,比如默认15加到30;
  • 修改新生代老年代比例,比如新生代老年代比例改为2:1
  • 修改e区和s区比例,比如改成6:2:2

2. 内存地址可变

存活对象在移动的时候内存地址会发生改变,可知句柄引用的内存地址并不是固定的值。

3. Eden区和Survivor区对象分配规则

对象优先分配到 Eden区,Survivor区是用来放每次GC过后的那些存活对象的。

假设Eden区和Survivor1区里有对象,一次Minor GC过后,存活对象全部进入Survivor2区域;接着新对象继续在Eden区里分配,Survivor2里放之前Minor GC后存活的对象(之前Eden和S区域),然后Survivor1区是空的;下一次Minor GC过后,剩余存活对象进入Survivor1区里,然后Survivor2区就是空的了。

新生对象仅仅放在Eden里,Survivor是用来放每一次Minor GC后存活的对象的。

4. 为什么老年代不采用复制算法,像新生代那样一个E两个S呢?或者说为什么新生代不采用标记整理算法?还有就是标记清除算法会产生内存碎片,那JVM中是在哪里用到了?

答:老年代存活对象太多了,如果采用复制算法,每次都挪动,可能90%的存活对象,这就不合适了。所以采用先把存活对象挪动到一起紧凑一些,然后回收垃圾对象的方式。

5. 触发Minor GC之前会如何检查老年代大小,涉及哪几个步骤和条件?

答:

1、 判断新生代存活是否大于老年代剩余

2、 条件1 成立且设置空间担保的情况下,判断老年代剩余是否大于之前进入老年代平均存活大小

6. 什么时候在Minor GC之前会提前触发一次Full GC?

答:新生代现有存活对象 > 老年代剩余内存情况下,未设置空间担保 或 空间担保失败。空间担保只保证老年代剩余内存满足新生代历次晋升的内存平均大小。

7. 每次Minor GC之前是否检查的是新生代的存活对象大小?还是说检查新生代所有对象大小?如果是后者,成本会不会很高?

答:每次Minor GC前直接检查新生代全部对象的大小是否小于老年代可以内存大小,不是检查新生代的存活对象的大小,所以这个比较成本是很低的。

8. Minor GC过后可能对应哪几种情况?

答:

情况1: Minor GC前先判断:存活的对象所占的内存空间 < Survivor区域内存空间的大小,那么存活的对象进入 Survivor区。

情况2:Minor GC前先判断:Survivor区域内存空间的大小 < 存活的对象所占的内存空间 < 老年代的可用空间大小。那么存活的对象,直接进入老年代。

情况3:Minor GC前先判断:(存活的对象所占的内存空间 > Survivor区域内存空间的大小) && (存活的对象所占的内存空间 > 老年代的可用空间大小)。那么会触发Full GC,老年代腾出空间后,再进行 Minor GC。如果腾出空间后还不能存放存活的对象,那么会导致OOM即堆内存空间不足、堆内存溢出。