JAVA常用的垃圾回收器

Serial收集器:(串行收集器)

这个收集器是一个单线程的收集器,但它的单线程的意义并不仅仅说明它只会使用一个CPU或一条收集线程去完成垃圾收集工作,更重要的是在它进行垃圾收集时,必须暂停其他所有的工作线程(Stop-The-World:将用户正常工作的线程全部暂停掉),直到它收集结束。收集器的运行过程如下图所示:
JAVA常用的垃圾回收器_第1张图片
上图中:
新生代采用复制算法,Stop-The-World
老年代采用标记-整理算法,Stop-The-World
当它进行GC工作的时候,虽然会造成Stop-The-World,但它存在有存在的原因:正是因为它的简单而高效(与其他收集器的单线程比),对于限定单个CPU的环境来说,没有线程交互的开销,专心做GC,自然可以获得最高的单线程手机效率。所以Serial收集器对于运行在client模式下是一个很好的选择(它依然是虚拟机运行在client模式下的默认新生代收集器)。

ParNew收集器:Serial收集器的多线程版本(使用多条线程进行GC)

ParNew收集器是Serial收集器的多线程版本。
它是运行在server模式下的首选新生代收集器,除了Serial收集器外,目前只有它能与CMS收集器配合工作。CMS收集器是一个被认为具有划时代意义的并发收集器,因此如果有一个垃圾收集器能和它一起搭配使用让其更加完美,那这个收集器必然也是一个不可或缺的部分了。收集器的运行过程如下图所示:
JAVA常用的垃圾回收器_第2张图片

上图中:
新生代采用复制算法,Stop-The-World
老年代采用标记-整理算法,Stop-The-World

ParNew Scanvenge收集器

类似ParNew,但更加关注吞吐量。目标是:达到一个可控制吞吐量的收集器。
停顿时间和吞吐量不可能同时调优。我们一方买希望停顿时间少,另外一方面希望吞吐量高,其实这是矛盾的。因为:在GC的时候,垃圾回收的工作总量是不变的,如果将停顿时间减少,那频率就会提高;既然频率提高了,说明就会频繁的进行GC,那吞吐量就会减少,性能就会降低。
吞吐量:CPU用于用户代码的时间/CPU总消耗时间的比值,即=运行用户代码的时间/(运行用户代码时间+垃圾收集时间)。比如,虚拟机总共运行了100分钟,其中垃圾收集花掉1分钟,那吞吐量就是99%。

G1收集器:

是当今收集器发展的最前言成果之一,知道jdk1.7,sun公司才认为它达到了足够成熟的商用程度。
优点:
  它最大的优点是结合了空间整合,不会产生大量的碎片,也降低了进行gc的频率。二是可以让使用者明确指定停顿时间。(可以指定一个最小时间,超过这个时间,就不会进行回收了)它有了这么高效率的原因之一就是:对垃圾回收进行了划分优先级的操作,这种有优先级的区域回收方式保证了它的高效率。
如果你的应用追求停顿,那G1现在已经可以作为一个可尝试的选择;如果你的应用追求吞吐量,那G1并不会为你带来什么特别的好处。
注:以上所有的收集器当中,当执行GC时,都会stop the world,但是下面的CMS收集器却不会这样。

CMS收集器:(老年代收集器)

CMS收集器(Concurrent Mark Sweep:并发标记清除)是一种以获取最短回收停顿时间为目标的收集器。适合应用在互联网站或者B/S系统的服务器上,这类应用尤其重视服务器的响应速度,希望系统停顿时间最短。
CMS收集器运行过程:(着重实现了标记的过程)
(1)初始标记
  根可以直接关联到的对象
  速度快
(2)并发标记(和用户线程一起)
  主要标记过程,标记全部对象
(3)重新标记
  由于并发标记时,用户线程依然运行,因此在正式清理前,再做修正
(4)并发清除(和用户线程一起)
  基于标记结果,直接清理对象
整个过程如下图所示:
JAVA常用的垃圾回收器_第3张图片

上图中,初始标记和重新标记时,需要stop the world。整个过程中耗时最长的是并发标记和并发清除,这两个过程都可以和用户线程一起工作。
优点:
  并发收集,低停顿
缺点:
(1)导致用户的执行速度降低。
(2)无法处理浮动垃圾。因为它采用的是标记-清除算法。有可能有些垃圾在标记之后,需要等到下一次GC才会被回收。如果CMS运行期间无法满足程序需要,那么就会临时启用Serial Old收集器来重新进行老年代的收集。
(3)由于采用的是标记-清除算法,那么就会产生大量的碎片。往往会出现老年代还有很大的空间剩余,但是无法找到足够大的连续空间来分配当前对象,不得不提前触发一次full GC。
疑问:既然标记-清除算法会造成内存空间的碎片化,CMS收集器为什么使用标记清除算法而不是使用标记整理算法:
答案:
CMS收集器更加关注停顿,它在做GC的时候是和用户线程一起工作的(并发执行),如果使用标记整理算法的话,那么在清理的时候就会去移动可用对象的内存空间,那么应用程序的线程就很有可能找不到应用对象在哪里。

参考博文:http://www.knowsky.com/889010.html

你可能感兴趣的:(jdk基础)