标签:gc
Java经过近20年的演变,已经发展出一套复杂、健壮和高性能的垃圾收集器。在不同的应用场合下使用不同的GC组合能让程序性能得到可观提高。我想这也是Java这么多年来一直处于不败之地的原因之一。
以下讨论只限于Server模式下的HotSpot JVM。
Sun/Oracle的HotSpot JVM为我们提供了多种不同的GC,一种GC只专门负责新生代或老年代的内存回收工作,所以实际使用的时候需要我们为新生代和老年代指定不同的GC。但G1例外,因为G1可以通吃整个堆内存。
Serial GC是最基本也是年纪最大的GC,它由Sun随第一版本的Java一同发布。 Serial是一个单线程的、 用于新生代的 GC,因此它在工作的只有一个线程来完成GC,同时还必须让JVM 暂停执行所有用户线程,即有名的Stop The World。 这就意味着程序会有较长时间的停顿。所以对于服务端应用来说,Serial GC基本无用武之地,JVM默认也不会在新生代选用此GC。
ParNew GC基本上是Serial GC的多线程版本,即在新生代的GC过程中会有多个线程线程同时执行清理,其它与Serial无异。因为是多线程,所以在多CPU环境下,它的性能会比Serial强一些。但如果是单CPU环境,它会带来线程上下文切换的时间开销,性能反而会不如Serial。ParNew是Server模式下的JVM的默认新生代收集器
该收集器也是一个作用于新生代的并行的多线程收集器,它与ParNew最大的区别在于它更加关注吞吐量(吞吐量 = 运行用户代码的时间 / (运行用户代码时间 + GC执行的时间) )。为了达到此目的,该GC提供了-XX:MaxGCPauseMillis
参数和-XX:GCTimeRatio
来控制吞吐量。前者是一个大于0的毫秒值,GC会尽可能保证垃圾收集耗时不超过该值。后者是一个大于0小于100的整数,意为垃圾收集耗时占总运行时间的比例。一般情况下,如果你的程序不是特别需要对GC吞吐量进行优化的话也不会手动指定使用该GC。
在名称后面加上old意为该GC是为老年代服务的。前者在老年代回收时与前面提到的Serial相同,即单线程,会造成较长的停顿。后者相当于多线程版本,工作时也会先暂所有用户线程,然后仅仅是会启动多个线程执行GC而已。
CMS(Concurrent Mark Sweep)是一种以尽可能减少回收停顿时间为目标的收集器,只能作用于老年代。前面的的GC在执行回收算法时,必须先将挂起所有用户线程,待GC完成后用户线程才得以继续执行。CMS与之最大的区别是,CMS的回收过程可以部分并发地与用户线程同时执行。 CMS的回收分为以下几个阶段:
其中,最耗时的步骤2和4是并发执行的,即用户线程不需要停顿,回收可以与用户线程同时执行,这样就能大大缩短Stop The World的时间。但这并不意味着CMS就是个非常完美的GC了,它还有以下几个主要缺点:
Concurrent Mode Failure
错误。因为CMS在执行并发标记时,用户线程也在执行,因此在标记的同时还会有新垃圾在不断产生,这部分垃圾称为浮动垃圾,这是CMS无法进行回收处理的,只能等待下一次GC再说。也正是由于GC时用户线程还会执行,CMS必须在开始GC之前为用户线程预留一部分内存空间以供使用,而这是有风险的。这部分空间不够用户线程使用, 就会导致Concurrent Mode Failure, JVM会被迫启用Serial Old触发一次Full GC, 而执行一次Full GC的耗时是比较长的。PS:
- Minor GC: 指的是对新生代进行垃圾回收的过程,这个过程一般会非常迅速。
- Full GC: 指对老年代执行的GC过程,在执行Full GC之前也可能会先执行一次Minor GC。Full GC通常会比Minor GC慢很多。
G1是目前垃圾收集技术发展的最新成果之一,它与前面的几款GC最大的不同在于:
除此之外,G1与CMS也是并发执行的GC,即执行清理时可以与用户线程同时(并发)执行,但是G1可以做到比CMS更短暂的停顿时间。
-XX:UseG1GC
参数命令JVM使用G1。
-XX:+UseConcMarkSweepGC
即命令JVM在老年代使用CMS,以提高GC性能。
标签:gc
原文地址:http://blog.csdn.net/neosmith/article/details/45105369