1.复制算法(JVM新生代回收算法)
在堆区中,对象分为新生代(年轻代)、老年代和永生代,而复制算法发生是发生在新生代的。新建的对象一般分配在新生代的Eden区,当Eden快满时进行一次小型的垃圾回收。存活的对象会移动到 Survivor1区(以下简称S1)。当再次发生 GC 时,S1区的存活对象将复制到先前闲置的S2区,同时存活对象寿命+1;以后每次发生GC,S1和S2区将交替的作为存活对象的存放区和闲置区。并且如果存活对象的寿命达到某个阈值,它将被分配到老年代中。
复制算法的缺陷:利用率只有一半,很明显S1区和S2区总会有一个要闲置下来。
小提问:我们知道年轻代分配堆内存的1/3,而Eden区和S1区,S2区的比例为8:1:1,为什么要这样设计?
老年代主要存放生命周期长的对象和大对象,所以分配2/3的堆空间。而新生代又分为Eden区,S1区和S2区,经验表明,一次GC,98%的Eden区对象会被回收,所以我们可以另外设计S1区和S2区去实现复制算法,而不需要创建两个和Eden区一样大的空间实现复制算法。
但是总有例外,如果我们一次GC将存活对象都移到S2区,S2区满了,Eden区还有存活对象,此时S2区age较大的直接晋级老年代。
2.标记清除算法(JVM老年代回收算法)
执行效率比较低,存在内存碎片,再次分配对象时可能会提前触发GC。
3.标记整理算法(JVM老年代回收算法)
比标记清楚多做了一部,将内存空间规整,避免了内存碎片。
4.CMS垃圾回收器
CMS垃圾回收器采用标记清除算法,用于老年代垃圾回收。
CMS 处理过程有七个步骤:
1. 初始标记(CMS-initial-mark) ,会导致用户线程停止(时间短);
2. 并发标记(CMS-concurrent-mark),与用户线程同时运行;
3. 预清理(CMS-concurrent-preclean),与用户线程同时运行;
4. 可被终止的预清理(CMS-concurrent-abortable-preclean) 与用户线程同时运行;
5. 重新标记(CMS-remark) ,会导致用户线程停止(时间短);
6. 并发清除(CMS-concurrent-sweep),与用户线程同时运行;
7. 并发重置状态等待下次CMS的触发(CMS-concurrent-reset),与用户线程同时运行;
cms运行流程图如下所示:
CMS有几个缺点:
1>也是标记清除算法的缺点,会产生内存碎片;
2>并发清理的过程中也会产生新的垃圾,这部分垃圾不会被清理;