JVM之垃圾收集器

来源:互联网 发布:js通过id获取div 编辑:程序博客网 时间:2024/05/04 07:03

现有的垃圾收集器:

年轻代:serial收集器,ParNew收集器,Parrallel Scavenge收集器

老年代:CMS收集器,Serial Old收集器,Parallel Old收集器

新的G1收集器。

不是每种收集器都可以相互搭配使用,可以搭配的组合有:

serial+CMS,serial+Serial Old,ParNew+CMS,ParNew+Serial Old,Parallel Scavenge+Serial Old,Parallel Scavenge+Parallel Old

这几种搭配方式。


Serial收集器与serial old收集器:单线程收集器,在进行垃圾收集时,停止其他所有工作线程,serila应用复制算法回收年轻代,serial old使用标记整理算法回收老年代。

这种收集器简单高效,没有线程切换的开销。serial old收集器还可以用于CMS收集器的备用方案。


ParNew收集器:是serial的多线程版本,在单cpu环境中,ParNew收集器的效率并不会比serial收集器效率高,因为有线程交互的开销。但是在多CPU下,效率会变好。一般默认情况下垃圾回收的线程数是cpu的数量。可以使用-XX:ParallelGCThreads设置线程数,使用-XX:UseConcMarkSweepGX的默认收集器,也可以使用-XX:+UseParNewGC来强制使用它。下图是ParNew+Serial Old的组合。



Parallel ScaVenge收集器:与ParNew收集器的区别在于关注点不同,其余收集器关注的是缩短垃圾回收时用户线程停顿时间,而它关注的是吞吐量,吞吐量=用户线程运行时间/(用户线程运行时间+GC停顿时间)。主要是和用在后台运算而不需要太多交互的任务。有两个参数用来控制吞吐量,-XX:MaxGCPauseMillis控制最大的垃圾回收时间,-XX:GCTimeRatio设置吞吐量大小。

其中-XX:MaxGCPauseMillis是大于零的数毫秒数,但是并不是越小越好,因为这里GC时间的缩短是牺牲吞吐量和新生代空间来换取的。越小空间的新生代收集肯定比大空间新生代收集快,也导致了收集更加的频繁。

-XX:GCTimeRatio是0~100的整数,比如19,表示允许的最大GC时间是1/(1+19)=5%。

还有一个参数是-XX:+UseAdaptiveSizePolicy,当这个参数打开后,不用再设置新生代(-Xmn),eden与survivor的比例(-XX:SurvivorRatio),晋升老年代对象大小(-XX:PretenureSizeThreshold)等参数,虚拟机会根据系统的运行情况收集性能监控,动态调整这些参数以提供最合适的停顿时间或者最大吞吐率。


Parallel Old收集器:是老年代的多线程收集版本,与Parallel ScaVenge配合使用。



CMS收集器:使用标记清除算法,作用于老年代。包括四个步骤:

1.初始标记

2.并发标记

3.重新标记

4.并发清除

初始标记和重新标记也会 stop the world,但是初始标记仅仅是标记GC roots直接关联的对象,速度很快。重新标记就是修正在并发标记阶段由于用户线程执行导致标记产生变动的那一部分对象的标记记录。并发标记就是GC roots可达性分析的过程。

整个过程最耗时的就是并发标记和并发清除,此时用户线程可以同时工作。


CMS收集器会很大程度减少了stop the world时间,但是也有以下几个缺点:

1.对CPU非常敏感,并发阶段,会因为GC线程占用了一部分CPU导致用户线程响应变慢,默认CMS启用(CPU数量+3)/4的数量。

2.CMS无法处理浮动垃圾:在并发清理阶段由于工作线程还在执行,会产生新的垃圾,这一部分垃圾无法被标记和清除,只能等到下一次垃圾回收清理,这一部分垃圾叫做“浮动垃圾”。因为在垃圾回收时,用户线程还在执行,所以不能等到老年代几乎满了才开始回收,需要预留一部分空间给用户线程使用。默认情况下在老年代占用了69%就会激活一次垃圾回收。可以使用-XX:CMSInitiltingOccupancyFraction设置这个比例。如果在CMS运行期间预留的空间无法满足用户线程,就会产生“Concurrent Mode Failure”失败,虚拟机会采用后背方案进行一次垃圾回收:使用serial old收集器进行一次老年代回收。

3.因为CMS采用标记清理算法,产生空间碎片,可以使用参数-XX:+UseCMSCompactAtFullCollection,用于在进行fullgc时开启内存碎片整理合并过程,这个过程是无法并发的。使用参数-XX:CMSFullGCsBeforeCompaction设置执行多少次不压缩的full gc后,跟着执行一次带压缩的。默认是0,每次fullgc都要进行碎片整理。


G1收集器:有以下特点:

1.并行与并发:充分利用多核、多CPU的硬件环境,缩短stop the world时间

2.分代收集:可以独立管理整个堆空间

3.空间整合:整体式基于标记整理算法,局部上是基于复制算法,所以不会产生空间碎片

4.可预测停顿:可以建立一个可预测的停顿时间模型,能让使用者明确在一个长度为M毫秒的时间内,消耗在垃圾收集上的时间不得超过N毫秒

G1收集器将整个堆划分为多个大小相等的region,跟踪各个region里面的垃圾堆积的价值大小(回收所需要的时间和回收所获得空间大小),在后台维护一个优先列表,每次根据允许的收集时间优先收集价值大的区域。

这会有一个问题产生,一个region中的对象不可能只被所在region对象引用,可以被其他region中对象引用,但是有不能每次回收一个region都扫描所有的Region,在其他收集器中老年代与新生代也有相同的问题,虚拟机是如下解决的:

G1中每隔region都有一个与之对应的Remembered Set,虚拟机发现程序对引用类型进行写操作时,会产生一个write barrier来展示中断写操作,检查引用的对象是否处于同一个region中(在老年代与新生代中,就是检查时候老年代的对象引用了新生代的对象),如果在不同的region中,则把相关引用信息记录到被引用对象所属的region对应的Remembered Set中。回收时,在进行GC roots枚举时加上Remembered Set即可。

不包含维护Remembered Set,G1有以下几个步骤:

1.初始标记

2.并发标记

3.最终标记

4.筛选回收



原创粉丝点击