1.标记复制(Mark-Copying)算法:
当我们调用 new 指令时,它会在 Eden 区中划出一块作为存储对象的内存。当 Eden 区的空间耗尽了怎么办?这个时候 Java 虚拟机便会触发一次 Minor GC,来收集新生代的垃圾。存活下来的对象,则会被送到 Survivor 区。
新生代共有两个 Survivor 区,我们分别用 from 和 to 来指代。其中 to 指向的 Survivior 区是空的。当发生 Minor GC 时,Eden 区和 from 指向的 Survivor 区中的存活对象会被复制到 to 指向的 Survivor 区中,然后交换 from 和 to 指针,以保证下一次 Minor GC 时,to 指向的 Survivor 区还是空的。
Java 虚拟机会记录 Survivor 区中的对象一共被来回复制了几次。如果一个对象被复制的次数为 15(对应虚拟机参数 -XX:+MaxTenuringThreshold),那么该对象将被晋升(promote)至老年代。另外,如果单个Survivor 区已经被占用了 50%(对应虚拟机参数 -XX:TargetSurvivorRatio),那么较高复制次数的对象也会被晋升至老年代。
万一存活对象数量比较多,那么To域的内存可能不够存放,这个时候会借助老年代的空间。
因此Minor GC使用的则是标记-复制算法。将 Survivor 区中的老存活对象晋升到老年代,然后将剩下的存活对象和 Eden 区的存活对象复制到另一个 Survivor 区中。理想情况下,Eden 区中的对象基本都死亡了,那么需要复制的数据将非常少,因此采用这种标记 - 复制算法的效果极好。
口诀:复制必交换,谁空谁为to
2.标记清除(Mark-Sweep算法):
老年代一般是由标记清除或者是标记清除与标记整理的混合实现。
标记清除算法一般应用于老年代,因为老年代的对象生命周期比较长。该算法先对所有可访问的对象,做个标记再遍历堆,把未被标记的对象回收(标记活的)。
缺点:
①回收时,应用需要挂起,也就是stop the world,导致用户体验非常差劲
②由于需要遍历全堆对象,效率比较低(递归与全堆对象遍历)。
③造成内存碎片化
3.标记压缩(Mark-Compact)算法:
标记清除算法和标记压缩算法非常相同,但是标记压缩算法在标记清除算法之上解决内存碎片化。
优点:解决内存碎片化问题。也消除了复制算法当中,内存减半的高额代价
缺点:效率低,压缩阶段,由于移动了可用对象,需要去更新引用。
4.标记清除压缩(Mark-Sweep-Compact)算法:
标记清除压缩(Mark-Sweep-Compact)算法是标记清除算法和标记压缩算法的结合算法。其原理和标记清除算法一致,只不过会在多次GC后,进行一次Compact操作!