垃圾回收算法:
1.标记清除算法:将所有需要回收的对象进行标记,标记结束后对标记的对象进行回收,但是效率低,会造成大量的碎片。
2.复制算法: 复制算法将空间分为两部分,每次使用其中的一部分。当一块内存用完了,就将这块的所有对象复制到另一块,将已使用的块清除。不会产生碎片,但是会浪费一定的内存空间。 在堆中的年轻代使用该算法,因为年轻代的对象多为生存周期比较短的对象。年轻代将内存分为一个Eden,两个survivor。每次使用Eden与一个survivor。当回收时,将survivor与Eden中存活的对象复制到另一个survivor,最后清理掉Eden与survivor。当survivor与Eden中存活的对象大小超过另一个survivor,则需要老年代来担保。
3. 标记整理算法:复制算法在对象存活率较高时,复制会使得效率降低。根据老年代的特点,使用标记整理算法。标记之后将所有存活的对象移向一端,将其他的清理。解决了碎片问题。
4.分代收集算法:在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。在老年代中,因为对象存活率高、没有额外空间对它进行分配担保,就必须使用“标记—清理”或者“标记—整理”算法来进行回收。
垃圾回收器:(Serial、ParNew、Parallel Scavaenge 、Serial Old、Parallel Old、CMS、G1)适用于要求高吞吐量(throughput)的应用,但停顿时间(pause time)会比较长,所以对web应用来说就不合适,因为这意味着用户等待时间会加长。而并行收集器可以理解时多线程串行收集,在串行收集基础上采用多线程方式进行GC,很好的弥补了串行收集的不足,可以大幅缩短停顿时间,因此对于空间不大的区域(如年轻代),采用并行收集器停顿时间很短,回收效率高,适合高频率执行。
Serial收集器是单线程的收集器,在进行垃圾回收时,需要停止其他的所有工作线程。
ParNew收集器时Serial的多线程版本。在单线程的环境下,parnew绝不比serial收集器具有更改的效果,因为存在着线程的开销,但是随着cpu的增加,便可以体现出优势。默认情况下线程个数与cpu数量相同。
Parallel Scavenge收集器:年轻代收集器,多线程并行收集,使用复制算法,与parnew相似。CMS,Parnew,Serial的设计目标是为了缩短用户线程的停顿时间。但是parallel scavenge的设计目标时实现一个可控的吞吐量(cpu运行用户代码时间/cpu消耗的总时间)。可以设置两个参数最大垃圾收集停顿时间、吞吐量大小,但是最大垃圾收集停顿
时间越小,系统设置的新生代越小,GC频率增加。
Serial Old 收集器:是serial在老年代的版本。
CMS:是一种获取最短停顿时间为目标的收集器。基于标记清除(老年代唯一一个基于标记清除的算法,除G1外)的算法实现。整个过程有四个步骤:初始标记、并发标记、重新标记、并发清除,其中初始标记与重新标记仍要停顿所有用户线程。初始阶段,主要负责标记gcroot能直接关联的对象,速度很快;并发标记是从GCRoot开始继续向下标记;重新标记是统计那些在并发标记过程中发生变化的标记;这个阶段的时间要比初始标记长,但是低于并发标记。并发清除是清除老年代中的垃圾。
CMS存在缺点:1.采用标记清除的算法(老年代唯一一个采用标记清除的算法),会产生碎片。 2.不能处理浮动垃圾(浮动垃圾:在并发清除时,用户线程还在运行,还会有新的垃圾产生,这部分只能等到下次GC时清理)。 3.对cpu特别敏感。由于CMS在GC时,最耗时的并发标记与并发 清除是与用户线程同时执行的,因此可以降低停顿时间,但是并发标记时会占用一部分的cpu资源,导致应用程序变慢。
G1收集器:唯一一个可以同时用于年轻代与老年代的垃圾收集器。G1收集器采用标记整理的算法,避免碎片。使用该收集器时,其堆的内存布局就发生变化,将堆分为不同的大小相等的region(每个region有一个remembered Set,为了避免做可达性分析是扫描这个堆,当引用在不同的region之间时,则将相关引用信息记录到remembered Set中),避免在整个堆中进行全区域的垃圾收集,能建立可预测的停顿时间模型。整个过程包括如下四个步骤:初始标记、并发标记、最终标记、筛选回收。初始标记与并发标记与CMS相似;最终标记:将并发标记阶段那些发生变化的对象的变化记录写入线程remembered set log,同时与remembered set合并;筛选回收阶段:通过对每个region的价值和成本进行筛选,已得到一个最好的回收方案,并回收。