(1).复制收集算法
针对Young区,依次扫描这个区的所有可达对象(如何确定可达对象,请参考前一节),扫描只扫描GC维护的一张对象关系有向图(以下称为可达对象链),只要在这个图上的,就将这个对象复制到另一个区域(实现这种算法需要堆内存保留一个与Young区大小一样的区域),原先的Eden区对象,移到From区,From区移到To区,有必要的话,将对象移到Old区(区域划分,见Java内存结构),原先内存全部清空,作为下一次GC用。
优缺点:只需遍历可达的对象,不用访问不可达对象,遍历少,但需要巨大的复制成本和较多的内存。
(2).标记清除算法
遍历可达对象链,对这些对象进行标记,下次,遍历整个区域的对象,没有标记的清除。
优缺点:不需要额外空间,但是遍历空间花费大,而且会产生大量内存碎片
(3).标记整理算法
前二者的结合,遍历可达对象链,标记这些对象,再按顺序将这些对象合并到一块内存上,比如,有1、2、3、4、5、6、7、8块连续内存对象,其中2,5,8是可达链上对象,标记整理算法的做法是:先标记他们,再从1开始遍历,1不是,到2,2是,将2复制到1,2标记清除,再遍历3,4,不是,遍历5,是,将5复制到2,依次如此,最后得到1,2,3有用内存,后面内存就被清除了。
优缺点:相对标记清除来说,没有了内存碎片,但是遍历花费仍然很大。
GC垃圾垃圾收集器
(1).串行垃圾回收器
GC线程只有一个,它会暂停所有工作线程,一个一个内存区域来收集,不适合服务器环境。通过JVM命令-XX:+UseSerialGC可以使用串行垃圾回收器。串行回收器也有两种:1.Serial:只对新生代使用;2.Serial Old:只对老年代使用,采用的算法不一样(一般作为CMS的替补)
(2).并行垃圾回收器
GC使用多线程进行垃圾回收。通过JVM命令-XX:+UseParallGC可以使用并行垃圾回收器。并行回收器有三种:1.ParNew,作用于新生代; 2.Parallel Scavenge 作用于新生代,但以吞吐量为主;3.Parallel Old,作用于老年代,也已吞吐量为主,配合2使用。
(3).并发标记扫描垃圾回收器(CMS)
多线程,标记清理(Full GC的时候用)通过JVM命令 -XX:+UseConcMarkSweepGC使用, 主要用于老生代,策略为:
年老代只有两次短暂停,其他时间应用程序与收集线程并发的清除。采用两次短暂停来替代标记整理算法的长暂停,它的收集周期:
初始标记(CMS-initial-mark) -> 并发标记(CMS-concurrent-mark) -> 重新标记(CMS-remark)->并发清除(CMS-concurrent-sweep) ->并发重设状态等待下次CMS的触发(CMS-concurrent-reset)。
它的主要适合场景是对响应时间的重要性需求大于对吞吐量的要求,能够承受垃圾回收线程和应用线程共享处理器资源,并且应用中存在比较多的长生命周期的对象的应用。但CMS收集算法在最为耗时的内存区域遍历时采用多线程并发操作,对于服务器CPU资源不够的情况下,其实对性能是没有提升的,反而会导致系统吞吐量的下降;
(4).G1垃圾回收器
适用于堆内存很大的情况,它将对内存分割成不同的区域,并且并发的对其进行回收,回收后对剩余内存压缩,标记整理,服务器端适用。