java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > JVM常用垃圾收集器及GC算法

JVM常用垃圾收集器及GC算法解读

作者:云淡风qin

这篇文章主要介绍了JVM常用垃圾收集器及GC算法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

GC的种类

1.Minor GC

对象从新生代区域消失的过程,我们称之为 “minor GC”。

清理整个YouGen(年轻代)的过程,eden、S0\S1的清理都会由于MinorGC Allocation Failure(YoungGen区内存不足),而触发minorGC。

2.Major GC

OldGen区内存不足,触发Major GC。

3.Full GC

Full GC 是清理整个堆空间—包括年轻代和永久代。

Full GC 触发的场景:

1)手动调用 System.gc()2)promotion failed (年代晋升失败,比如eden区的存活对象晋升到S区放不下,又尝试直接晋 升到Old区又放不下,那么Promotion Failed,会触发FullGC)

3)CMS的Concurrent-Mode-Failure 由于CMS回收过程中主要分为四步:

4)新生代晋升的平均大小大于老年代的剩余空间 (为了避免新生代晋升到老年代失败) 当使用G1,CMS 时,FullGC发生的时候 是 Serial+SerialOld。 当使用ParalOld时,FullGC发生的时候是ParallNew +ParallOld.

GC的判定

1.引用计数法:指的是如果某个地方引用了这个对象就+1,如果失效了就-1,当为 0 就会回收但是 JVM 没有用这种方式,因为无法判定相互循环引用(A 引用 B,B 引用 A)的情况。

2.引用链法(可达性分析/根搜索): 通过一种 GC ROOT 的对象(方法区中静态变量引用的对象等-static 变量)来判断,如果有一条链能够到达 GC ROOT 就说明该对象不能回首,不能到达 GC ROOT 就说明可以回收

GCRoots有哪些

但是当满足上述条件时,一个对象比不一定会被回收

当一个对象不可达 GC Root 时,这个对象并不会立马被回收,而是出于一个死缓的阶段,若要被真正的回收需要经历两次标记。

第二次被标记,这时,该对象将被移除”即将回收”集合,等待回收。

GC垃圾收集器

新生代收集器

1.Serial 垃圾收集器(单线程、复制算法)

串行收集器是最古老,最稳定以及效率高的收集器,使用停止复制方法,只使用一个线程去串行回收;垃圾收集的过程中会Stop The World(服务暂停);参数控制:使用-XX:+UseSerialGC可以使用Serial+Serial Old模式运行进行内存回收(这也是虚拟机在Client模式下运行的默认值) 

缺点:是串行效率较低。

2.ParNew 垃圾收集器(Serial+多线程)

ParNew收集器其实就是Serial收集器的多线程版本,使用停止复制方法。新生代并行,其它工作线程暂停。

参数控制:使用-XX:+UseParNewGC开关来控制使用ParNew+Serial Old收集器组合收集内存;使用-XX:ParallelGCThreads来设置执行内存回收的线程数。

3.Parallel Scavenge 收集器(多线程复制算法、高效)JDK1.8 默认采用的新生代收集器。

ParallelScavenge收集器类似ParNew收集器,Parallel收集器更关注CPU吞吐量,即运行用户代码的时间/总时间,使用停止复制算法。可以通过参数来打开自适应调节策略,虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或最大的吞吐量;也可以通过参数控制GC的时间不大于多少毫秒或者比例。

参数控制:使用-XX:+UseParallelGC开关控制使用Parallel Scavenge+Serial Old收集器组合回收垃圾(这也是在Server模式下的默认值);使用-XX:GCTimeRatio来设置用户执行时间占总时间的比例,默认99,即1%的时间用来进行垃圾回收。使用-XX:MaxGCPauseMillis设置GC的最大停顿时间(这个参数只对Parallel Scavenge有效),用开关参数-XX:+UseAdaptiveSizePolicy可以进行动态控制,如自动调整Eden/Survivor比例,老年代对象年龄,新生代大小等,这个参数在ParNew下没有。

老年代收集器

1.Serial Old收集器(单线程标记整理算法 )

老年代收集器,单线程收集器,串行,使用"标记-整理"算法(整理的方法是Sweep(清理)和Compact(压缩),主要是运行在 Client 默认的 java 虚拟机默认的年老代垃圾收集器。

2.Parallel Scavenge 收集器

多线程机制与Parallel Scavenge差不错,使用标记整理(与Serial Old不同,这里的整理是Summary(汇总)和Compact(压缩),汇总的意思就是将幸存的对象复制到预先准备好的区域,而不是像Sweep(清理)那样清理废弃的对象)算法,在Parallel Old执行时,仍然需要暂停其它线程。Parallel Old在多核计算中很有用。这个收集器是在JDK 1.6中,与Parallel Scavenge配合有很好的效果。

参数控制: 使用-XX:+UseParallelOldGC开关控制使用Parallel Scavenge +Parallel Old组合收集 器进行收集。

3.CMS 收集器(多线程标记清除算法)

Concurrent mark sweep(CMS)收集器是一种年老代垃圾收集器,其最主要目标是获取最短垃圾回收停顿时间,和其他年老代使用标记-整理算法不同,它使用多线程的标记-清除算法。

整个过程分为6个步骤,其中初始标记、重新标记这两个步骤仍然需要“Stop The World

优点:并发收集、低停顿

缺点:产生大量空间碎片、并发阶段会降低吞吐量

4.G1收集器

Garbage first 垃圾收集器是目前垃圾收集器理论发展的最前沿成果,相比与 CMS 收集器,G1 收集器两个最突出的改进是:

G1特点

G1 收集器避免全区域垃圾收集,它把堆内存划分为大小固定的几个独立区域,并且跟踪这些区域的垃圾收集进度,同时在后台维护一个优先级列表,每次根据所允许的收集时间,优先回收垃圾最多的区域。区域划分和优先级区域回收机制,确保 G1 收集器可以在有限时间获得最高的垃圾收集效率。

GC垃圾收集器的选择

JVM给了三种选择:串行收集器、并行收集器、并发收集器。

但是串行收集器只适用于小数据量的情况,所以这里的选择主要针对并行收集器和并发收集器。

吞吐量优先的并行收集器

如上文所述,并行收集器主要以到达一定的吞吐量为目标,适用于科学技术和后台处理等。Parallel Scavenge + ParallelOld

响应时间优先的并发收集器

如上文所述,并发收集器主要是保证系统的响应时间,减少垃圾收集时的停顿时间。适用于应用服务器、电信领域ParNew + CMS

GC垃圾收集算法

标记-清除算法 (Mark Sweep)

算法分为2个阶段:

标记算法分为两种:

1.引用计数算法(Reference Counting)

2.可达性分析算法(Reachability Analysis)。由于引用技术算法无法解决循环引用的问题,所以这里使用的标记算法均为可达性分析算法。 

缺点:产生了大量的非连续内存,内存碎片化严重,后续可能发生大对象不能找到可利用空间的问题。

复制算法 (Copying)

为了解决效率与内存碎片问题,复制(Copying)算法出现了,它将内存划分为两块相等的大小,每次使用一块,当这一块用完了,就讲还存活的对象复制到另外一块内存区域中,然后将当前内存空间一次性清理掉。这样的对整个半区进行回收,分配时按照顺序从内存顶端依次分配,这种实现简单,运行高效。

不过这种算法将原有的内存空间减少为实际的一半,代价比较高。 

缺点:可用内存变为原来的一半,长期存活的对象复制频率高

标记-整理算法(Mark-Compact)

标记阶段和 Mark-Sweep 算法相同,标记后不是清理对象,而是将存活对象移向内存的一端。然后清除端边界外的对象

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文