JAVA 1.7 GC

JavaGC算法及种类

各种GC步骤过程

GC算法主要有以下三种方法(都是以GCRoots可达性为依据,引用计数算法实现简单,但由于存在循环引用问题,故已不采用,详见:JavaGC(概述))

(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根据堆内存空间不同区域,采用不同的算法回收:

Young区:存活的对象较少,复制代价小,但次数多,采用复制收集算法;

Old区和方法区:对象存活较多,次数少,较慢,采用标记清除或标记整理算法。

以上,是GC的具体算法,即回收内存的做法,GC回收器种类实现上也有很多种。

再说明各种GC回收器之前,先说明下GC回收器的衡量指标:

1.Throughput(吞吐量):所有没有花在执行GC上的时间占总运行时间的比重。

2.Pauses(暂停):当GC在运行时程序的暂停次数。或者是在感兴趣的暂停次数中,暂停的平均时长和最大时长。

3.Footprint(足迹?):当前使用的堆内存大小(算法所有花费的额外空间)。

4.Promptness(及时性):不再使用的对象多久能被清除掉并释放其内存。

(1).串行垃圾回收器

GC线程只有一个,它会暂停所有工作线程,一个一个内存区域来收集,不适合服务器环境。通过JVM命令-XX:+UseSerialGC可以使用串行垃圾回收器。串行回收器也有两种:1.Serial:只对新生代使用;2.SerialOld:只对老年代使用,采用的算法不一样(一般作为CMS的替补)

(2).并行垃圾回收器

GC使用多线程进行垃圾回收。通过JVM命令-XX:+UseParallGC可以使用并行垃圾回收器。并行回收器有三种:1.ParNew,作用于新生代;2.ParallelScavenge作用于新生代,但以吞吐量为主;3.ParallelOld,作用于老年代,也已吞吐量为主,配合2使用。

(3).并发标记扫描垃圾回收器(CMS)

多线程,标记清理(FullGC的时候用)通过JVM命令-XX:+UseConcMarkSweepGC使用,主要用于老生代,策略为:

年老代只有两次短暂停,其他时间应用程序与收集线程并发的清除。采用两次短暂停来替代标记整理算法的长暂停,它的收集周期:

初始标记(CMS-initial-mark)->并发标记(CMS-concurrent-mark)->重新标记(CMS-remark)->并发清除(CMS-concurrent-sweep)->并发重设状态等待下次CMS的触发(CMS-concurrent-reset)。

它的主要适合场景是对响应时间的重要性需求大于对吞吐量的要求,能够承受垃圾回收线程和应用线程共享处理器资源,并且应用中存在比较多的长生命周期的对象的应用。但CMS收集算法在最为耗时的内存区域遍历时采用多线程并发操作,对于服务器CPU资源不够的情况下,其实对性能是没有提升的,反而会导致系统吞吐量的下降;

(4).G1垃圾回收器

适用于堆内存很大的情况,它将对内存分割成不同的区域,并且并发的对其进行回收,回收后对剩余内存压缩,标记整理,服务器端适用。

​发现一篇,针对GC垃圾回收的详细优质博客,可以参考:JVM调优和垃圾回收器说明(zhuangyalei)

相关推荐