jvm_垃圾回收学习笔记_2_垃圾收集算法(附面试题)

一、扯扯我们所了解JVM堆中的内存区域划分

    废话不多说,先上图:
jvm_垃圾回收学习笔记_2_垃圾收集算法(附面试题)_第1张图片
如图可知,堆中有着两个大的区域,分别是新生代和老年代。新生代中又分为一个较大的Eden区和两个较小的Survivor区(也有人叫s0和s1)。那么为什么要这样划分呢?经查资料得知,在目前的垃圾回收器中,大多数都是基于两个假说。弱分带假说:绝大多数对象都是朝生朝灭; 强分带假说:熬过越多垃圾收集过程的对象就越难消亡。正是基于这两个假说,堆中的区域才划分新生代和老年代。其中新生代和老年的比例默认为1:2,也正是因为‘弱分带假说’,所以新生代的大小设置的较小,老年代的大小稍大,至于为什么默认是1:2,可能是前人的经验所得吧,当然实际情况中式可以调整的。调整参数:-XX:NewSize 和 -Xmn:指定JVM启动时分配的新生代内存和新生代最大内存。-XX:OldSize:设置JVM启动分配的老年代内存大小-XX:NewRatio:指定老年代/新生代的堆内存比例。如果-XX:NewRatio=4表示年轻代与年老代所占比值为1:4
    而新生代为什么又分为一个较大的Eden区和两个较小的Survivor区呢?这个就是下面要说的垃圾回收算法了。Eden区和两个Survivor区的大小比默认是8:1:1。通过-XX:SurvivorRatio:设置新生代中1个Eden区与1个Survivor区的大小比值。在hotspot虚拟机中,新生代 = 1个Eden + 2个Survivor。如果新生代内存是10M,SurvivorRatio=8,那么Eden区占8M,2个Survivor区各占1M。设置。

二、标记-清除算法

    先上图:这里笔者只是知道这几种算法,暂时并没有了解具体如何实现的
jvm_垃圾回收学习笔记_2_垃圾收集算法(附面试题)_第2张图片
    标记-清除算法算是最简单的一种算法吧,简单粗暴。但是执行想想,它也是有缺点的。比如第一就是在其清除过一次以后,会产生大量不连续的内存碎片,而程序在分配内存空间时都是连续分配的,这样就会导致在程序需要分配大对对象时无法找到足够的连续空间而不得不进行一次gc操作;第二的话就是执行效率不稳定,在如果是高并发的情况下,对象生产的非常迅速,这时就必须进行大量的标记和清除动作,导致执行效率大大降低。所以后续的算法都是在此基础上进行改进的~

三、标记-复制算法

jvm_垃圾回收学习笔记_2_垃圾收集算法(附面试题)_第3张图片
    如图所示,标记-复制算法是利用空间换时间的一种算法,利用一半的区域作为保留区域,每次gc时将活着的对象复制到另外一块区域上,简单高效还没有内存碎片的问题,唯一的确定就是浪费内存空间。
    讲到这里大家应该发现了,标记-复制算法是应用在新生代的一种算法,新生代中的s0和s1区正是为此算法准备的。新生对象首先会进入Eden区,在Eden区满的时候会触发一次Minor GC,也叫Young GC。这时会将存活对象移至s0区;在第二次触发Minor GC时,会将Eden区的存活对象和s0区的存活对象移至s1区;在第三次触发Minor GC时,会将Eden区的存活对象和s1区的存活对象移至s0区,如此重复~当最后一次触发Minor GC时,如果此时Eden区和其中一个Survivor区都满了的情况下,会把一部分对象移至老年代里面去。具体是什么规则呢,以后再说,这里不涉及。。。

四、标记-整理算法

jvm_垃圾回收学习笔记_2_垃圾收集算法(附面试题)_第4张图片
    标记-整理算法不同于标记-清理算法的地方就是它不会产生内存碎片,而且不同于标记-复制算法需要浪费额外的空间。标记-整理算法是被应用于老年代得到一种算法。因为对象一旦进入老年代,基本上可以说是确定了它是很难被GC的了,可能是一直存在在内存中的,所以标记-整理算法和标记-复制算法都不适合它。但也正是因为老年代中的对象大部分都是永久保存的,所以每一次Major GC,也叫Old GC时,将如此多的对象在可能是并发的情况下移动至一起是个很负重的操作。所以设计者规定了在进行标记-整理操作时,其他线程必须停止工作,这个规定也被设计者描述为“stop the world”。

五。面试题

1、 请简述JVM中有那些垃圾回收算法,说说他们的应用场景。

    本博文中已经说明,不再解释~

2、新生代为什么要设置Eden区和两个Survivor区?

    本博文中已经说明,不再解释~

3、对象在什么情况下会进入老年代?

  1. 如果一个对象的大小比Eden区的大小还要大,此时对象会直接进入老年代。如果此时老年代的大小也不足以放下它,则会进行一次Old GC或Full GC,如果此时老年代内存够放的下它,就移至老年代,如果还是放不下,则报OutOfMemoryError异常。
  2. 长期存活的对象会进入老年代。对象在每经过一次Minor GC存活下来进入一个Survivor区后,该对象的年龄就会增加一岁(对象头中有4个比特位的空间存放年龄),当对象的年龄到达默认15岁时,对象会进入老年代。可以通过-XX:MaxTenuringThreshold=10来设置对象晋升老年代的阈值。
  3. 如果单个Survivor区中相同年龄(假设6岁)的所有对象大小的总和大于单个Survivor区大小的一半,此时无需等到对象到达最大年龄,就直接将大于等于6岁的对象全部移至老年代。

你可能感兴趣的:(jvm,垃圾回收)