JVM学习笔记(六)垃圾收集器

垃圾收集算法是内存回收的方法,而垃圾收集器是内存回收的具体实现。不同的虚拟机所用的垃圾收集器都不同,下图是Hotspot虚拟机在JDK1.7版本之后包含的收集器:

七个收集器所处的位置代表了他们是属于新生代收集器还是老年代收集器,两个收集器的连线代表着他们可以搭配使用。

1.Serial 收集器:他是最基本,发展历史最久的一个收集器,在JDK1.3.1之前是虚拟机新生代收集的唯一选择,看名字就知道他是一个单线程收集器,并且他的单线程的意义不仅仅是他只会使用一个CPU或者一条线程进行垃圾收集,更重要的是他在进行垃圾收集的时候必须暂停其他所有的工作线程(Stop The World),不过虽然它的这个特点体验很不好,但是它依然是虚拟机运行在Client模式下的默认新生代收集器,他的优点是简单而高效,对于单个CPU的环境来说,它没有线程之间的交互开销,单纯的进行垃圾收集自然可以获得最高的单线程效率。

2.ParNew 收集器:它其实就是Serial收集器的多线程版本,除了使用多线程进行垃圾收集之外,其余行为包括Serial收集器可用的参数,手机算法,Stop The World ,对象分配规则,回收策略等都相同,共用了许多的代码。他是许多默认在Server模式下的首选新生代收集器,主要的原因是除了Serial收集器之外目前只有他能与CMS收集器配合使用。

3.Parallel Scavenge 收集器:它是采用复制算法的收集器也是并行的多线程的收集器,它的特点是关注的是吞吐量,所谓吞吐量就是CPU用于运行用户代码的时间与CPU消耗时间的比值,吞吐量=运行用户代码的时间/运行用户代码的时间+垃圾收集时间,高吞吐量看可以高效率的利用CPU时间尽快完成程序的运算任务,主要适合在后台运算而不需要哦太多交互的任务。它提供了两个参数用于精确控制吞吐量,-XX:MaxGCPauseMillis参数,该参数使虚拟机将尽可能的保证内存回收花费的时间不超过设定值;-XX:GCTimeRatio,直接设置吞吐量的大小,默认值是99,也就是允许最大1%(1/1+99)的垃圾收集时间。除了这两个参数之外,还有一个参数-XX:+UseAdaptiveSizePolicy参数,这是一个开关参数,当这个参数打开之后,就不需要手工指定新生代的大小,Eden与Survivor区的比例,晋升老年代对象的大小等细节参数了,虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以达到最合适是的停顿时间或者最大吞吐量,这种调节方式称为自适应的调节策略(GC Ergonomics)

4.Serial Old 收集器:它是Serial的老年代版本,同样是一个单线程的收集器,采用标记-整理算法,主要意义也是在虚拟机的Client模式下使用,另外就是在server模式下,与Palallel Scavenge 收集器搭配使用或者是作为CMS的备用方案。

5.Parallel Old 收集器:它是Parallel收集器的老年代版本,使用多线程和标记-整理算法,在注重吞吐量以及CPU资源敏感的场合,都可以优先考虑Parallel Scavenge 和Parallel Old 的收集器组合。

6.CMS收集器:它是一种以获取最短回收停顿时间为目标的收集器,是基于标记-清除算法实现的,他的运作过程分为四个步骤,初始标记(CMS initial mark);并发标记(CMS concurrent mark);重新标记(CMS remark);并发清除(CMS concurrent sweep);其中    初始标记和重新标记仍然需要Stop The World,初始标记仅仅是标记一下GC Roots能直接关联的对象,速度很快,并发标记阶段就是进行GC Roots Tracing的过程,而重新标记阶段就是为了修正在并发标记中因用户程序继续运作而导致标记产生变化的一部分对象的标记,这个阶段的停顿时间会比初始标记阶段稍长一些。并发标记和并发清除的过程收集器线程与用户线程都可以一起工作,所以CMS的优点就是并发收集,低停顿,有些文档中也称之为并发收集低停顿收集器(Concurrent Low Pause Collector),但是他有以下三个主要的缺点:

(1)CMS收集器对CPU资源非常敏感,它虽然不会导致用户线程停顿但是会因为占用了一部分线程资源(或者说cpu资源)而导致应用程序变慢,总吞吐量会降低。

(2)CMS收集器无法处理浮动垃圾(Floating Garbage)可能出现“ Concurrent Mode failure ”失败而导致另一次的 Full GC。

    浮动垃圾:CMS并发清理阶段用户线程还在运行中,伴随着程序运行就会有新的垃圾不断产生,这一部分垃圾出现在标记过程之后,CMS无法在当次收集的时候处理掉他们,只好等待下一次的GC,这一部分就被称为浮动垃圾。所以CMS收集器在需预留一部分空间提供并发收集时的程序运作使用,当预留的内存无法满足程序需要时就会出现一次“ Concurrent Mode failure ”,这时虚拟机会启动后备方案,临时启用Serial Old收集器来重新进行老年代的垃圾收集,这样停顿的时间就会变长,导致性能下降。可以通过 -XX:CMSInitiatingOccupancyFraction参数设置收集器的启动阙值。

(3)CMS是基于标记-清除算法实现的,也就是收集结束后会有大量的空间碎片产生,这会给大对象的内存分配带来很大的麻烦,往往就是老年代还有很大空间剩余,但是无法找到足够大的连续空间类分配当前的对象,不得不提前触发一次Full GC。所以CMS提供了一个-XX:+UseCMSCompactAtFullCollection开关参数,默认是开启的用于在CMS收集器要进行Full GC的时候开启内存碎片的合并整理过程,但这个过程是无法并发的会导致停顿时间变长,所以可以通过-XX:CMSFullGCBeforeCompaction参数设置执行多少次不压缩的Full GC之后,来一次带压缩的Full GC,这个值默认是0表示每次进行Full GC时都进行碎片整理。

7.G1收集器(Garbage-First):是一款面向服务端应用的垃圾收集器,具备的特点如下

(1)并行与并发:能充分利用多CPU来缩短Stop-The-World停顿的时间,可以通过并发的方式让java程序继续执行。

(2)分代收集:分代的概念在G1中依然得以保留,能够采用不同的方式处理新创建的对象,已经存活了一段时间的对象和熬过多次GC的旧对象以获取更好的收集效果。

(3)空间整合:G1从整体看是基于标记-整理算法实现的,从局部(两个Region之间)来看是基于复制算法实现的,这两个算法都不会在运行期间产生内存空间碎片,收集后能提供完整的可用内存,这种特性有利于程序长时间运行,分配大对象时不会应为找不到连续的内存空间而提前触发下一次Full GC。

(4)可预测的停顿时间:G1除了追求低停顿外,还能建立可预测的停顿时间模型,能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒,这几乎可以达到实时java的垃圾收集器的特征了。

G1收集器之前的收集器收集的范围都是整个新生代或者老年代,而G1收集器是将整个java堆划分为多个大小相等的独立区域(Region),虽然还保留新生代和老年代的概念但是新生代和老年代不再是物理隔离的了,他们都是一部分不需要连续的Region的集合。G1可以有计划的避免在整个java堆中进行全区域的垃圾收集,G1会跟踪哥个Region中的垃圾堆积的价值大小(回收所获得的空间大小以及回收所需要的经验值),在后台维护一个优先列表,每次根据允许的收集时间,优先收集价值最大的Region,以获取可能高的收集效率。

G1收集器中的每个Region都有一个对应的Remembered Set 用来记录不处于同一个Region中的对象的相关引用信息到被引用对象所属的Region的Remembered Set中,比如分代收集中就是老年代引用了新生代中的对象。通过这种方式在内存回收时避免全堆扫描。不考虑维护Remembered Set的操作,G1收集器的运作大致可以分为以下几个步骤:初始标记——并发标记——最终标记——筛选回收,其中并发标记和筛选回收都是可以与用户线程并发执行的,最终标记是并行的。

 

并行(parallel):指多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状态

并发(Concurren)指用户线程与垃圾收集线程同时执行,(但不一定是并行的可能会交替执行)用户程序在继续运行,而垃圾收集程序运行于另一个CPU上

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值