jvm的垃圾回收算法有哪些

        jvm的垃圾回收算法有标记-清除、标记-复制、标记-整理、分代回收算法,它们分别有不同的实现:

标记-清除算法

        利用可达性分析算法分析之后,将未被标记的对象[即不可达对象]清除,以便回收它们所占用的内存。

        缺点:

        1、需要对内存进行两次遍历,一次遍历标记,一次遍历清除,效率较低;

        2、这种算法会造成大量的内存碎片,以至于出现当我们需要一片连续的大的内存空间去存储对象的时候无法找到合适的内存。

        CMS收集器就是用的标记-清除算法,CMS为了解决碎片式内存提供了内存合并整理的功能,但是这个功能的执行会导致用户线程暂停,会延长STW,导致程序性能下降。

标记-复制算法:

        为了解决清除算法的内存碎片问题,复制算法将内存一分为二,每次只使用一半的内存去存储对象,当这一半内存不够用的时候触发gc,将对象进行标记之后,将存活下来的对象移到另外一半内存,然后将当前这一半内存清空,以便在下一次gc的时候使用。

       缺点

        每次只能使用一半内存,内存使用率低,gc频繁。

       改进

        在新生代中,因为大部分的对象都是朝生夕死,每次gc存活下来的对象占比很少,所以将新生代按照8:1:1的比例划分为Eden、survivor from、survivor to三个区,每次minor gc时,都是将eden和一个survivor区存活下来的对象复制到另外一个survivor区,然后清空eden和对应的survivor区。虽然我们其实是无法保证每次minor gc过后存活下来的对象占比永远低于10%,但是有老年代为新生代做内存兜底,当存活下来的对象在另一个survivor区保存不下时,将这些对象转移到老年代。

标记-整理算法 

         先对对象进行标记,然后将存活下来的对象向内存的一端移动,然后回收不再存活的对象所占用的内存。标记整理算法是针对于老年代提出来的算法,因为老年代的大部分对象都是经过了很多次gc之后仍然存活的对象,这些对象生存率高,如果对它们使用复制算法的话,就会造成一次次的复制而浪费时间。

分代收集算法 

        因为新生代和老年代的对象有着不同的特点,新生代存放的是大部分的新创建的对象,这些对象大部分都是朝生夕死,因此每次minor gc都会有大量的对象被回收;而老年代的对象是经历了多次gc依然存活下来的对象,老年代中的对象存活率高。所以我们不适合将新生代和老年代的对象一起gc,新生代和老年代适合不同的gc算法,并且适合在不同的时机去触发gc。新生代使用复制算法,老年代使用标记整理或清除算法。现在的商用的虚拟机都是使用分代收集。 

CMS和G1 

        cms收集器只回收老年代,使用标记-清除算法;G1既回收新生代又回收老年代,使用标记-整理算法。

        CMS因为其使用的是标记-清除算法,所以会有个严重问题就是在gc之后产生大量的内存碎片,当我们无法找到一块儿足够大的连续内存去存储对象的时候,就不得不再一次触发gc。

        G1打破了原有的对于堆的分代概念,将堆分为一个个大小相等的region,并且提供了可预测的停顿时间模型,使得我们可以去设置在一定的时长内所期望的停顿时间,在执行gc的时候,会将region按照回收价值和回收耗时进行排序,依据我们所设置的期望停顿时间去生成一个回收方案,回收部分region。

        G1的优势很明显,它无需和其他的收集器配合,自己便可以回收新生代和老年代;它支持可预期的停顿时间,提高了gc的效率。

        

你可能感兴趣的:(jvm,算法)