原文地址:xeblog.cn/articles/24java
新生代均采用
复制
算法来回收内存。算法
最基本的、发展历史最悠久的单线程的收集器。在进行垃圾收集时,必须暂停其它全部的工做线程(Stop The World),直到它收集结束。它是 JVM
运行在 Client
模式下的默认新生代收集器,它比其它单线程的收集器更简单、更高效。可与 CMS 收集器
配合工做。bash
Serial 收集器
的多线程版本。它是许多运行在 Server
模式下的虚拟机首选的新生代收集器,在使用 -XX:+UseConcMarkSweepGC
选项后的默认新生代收集器,也能够经过 -XX:+UseParNewGC
选项强制指定它。它除了是多线程收集以外,其它和 Serial 收集器
基本同样,它默认开启的收集线程数与 CPU
的数量相同,在 CPU
很是多的环境下,可经过 -XX:ParallelGCThreads
参数限制垃圾收集的线程数。可与 CMS 收集器
配合工做。多线程
并行的多线程收集器,它的目标是达到一个可控的吞吐量(吞吐量是 CPU
用于运行用户代码的时间与 CPU
总消耗时间的比值)。并发
吞吐量 = 运行用户代码的时间 / (运行用户代码的时间 + 垃圾收集时间)
复制代码
高吞吐量能够高效的利用 CPU
时间,尽快的完成程序的运算任务,主要适合在后台运算而不须要太多交互的任务。Parallel Scavenge 收集器
提供了两个参数用于精确控制吞吐量: -XX:MaxGCPauseMillis
和 -XX:GCTimeRatio
。性能
容许一个大于0的毫秒数,收集器将尽量保证内存回收花费时间不超过这个设定的值,它是以牺牲吞吐量和新生代空间来缩短 GC
停顿时间的。spa
容许一个大于0且小于100的整数,垃圾收集时间占总时间的比率。线程
这是一个开关参数,当它打开后,就不须要手动指定新生代的大小(-Xmn),Eden
与 Survivor
区的比例(-XX:SurvivorRatio)、晋升老年代对象年龄(-XX:PretenureSizeThreshold)等细节参数了,虚拟机会根据当前系统的运行状况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或最大的吞吐量。3d
老年代采用
标记-整理
或标记-清除
算法来回收内存。code
它是 Serial 收集器
的老年代版本,也是一个单线程收集器,使用 标记-整理
算法。这个收集器的主要意义也是在于给 Client
模式下的虚拟机使用,若是是在 Server
模式下,那么它主要还有两大用途:
JDK1.5
以及以前版本中与 Parallel Scavenge 收集器
搭配使用。CMS收集器
的后备预案,在并发收集发生 Concurrent Mode Failure
时使用。它是 Parallel Scavenge 收集器
的老年代版本,使用多线程和 标记-整理
算法。
它是一种并发的、以获取最短回收停顿时间为目标的收集器,使用 标记-清除
算法实现的。运行过程较为复杂,整个过程分为4个步骤:
初始标记、从新标记仍须要暂停其它全部的工做线程,初始标记仅仅只是标记一下 GC Roots
能直接关联到的对象,速度很快。并发标记阶段就是进行 GC Roots
的可达性分析过程,而从新标记阶段则是为了修正并发标记期间因用户线程继续运做而致使标记产生变更的那一部分对象的标记记录,这个阶段的停顿时间通常会比初始标记阶段稍长一些,但远比并发标记的时间短。CMS 收集器
存在3个明显的缺点:
CMS收集器
会占用一部分线程而致使应用程序变慢,总吞吐量会下降。CMS
默认启功的回收线程数是(CPU数量 + 3)/ 4
,至关于当 CPU
在4个以上时,并发回收时垃圾收集线程很多于 25%
的 CPU
资源,并随着 CPU
数量的增长而降低。当 CPU
不足4个时,CMS
对用户线程的影响就可能变得更大。CMS收集器
没法处理浮动垃圾,可能出现 Concurrent Mode Failure
失败而致使另外一次 Full GC
的产生。因为 CMS
并发清除阶段用户线程还在运行着,伴随程序运行天然就还会有新的垃圾不断产生,这一部分垃圾出如今标记过程以后,CMS
没法在当次收集中处理掉它们,只好留在下一次 GC
时再清理掉,这一部分垃圾就称为浮动垃圾。CMS收集器
使用的是 标记-清除
算法,因此垃圾回收后会产生大量的空间碎片。CMS
提供 -XX:+UseCMSCompactAtFullCollection
的开关参数(默认开启),用于在 CMS
收集器顶不住要进行 Full GC
时开启内存碎片的合并整理过程,这个过程是没法并发执行的,虽然空间碎片没了,可是停顿时间不得不变长。
G1收集器
是当今收集器技术发展的最前沿成果之一。
上面所介绍的收集器,都只是负责 Java堆
中的一部份内存(新生代或老年代),而 G1
就不一样了,它全干。
G1
将整个 Java堆
划分为多个大小相等的独立区域(Region),虽然还保留有新生代和老年代的概念,可是这两部份内存再也不是物理隔离的,它们都是一部分不须要连续的 Region
的集合了。
具有的特色:
G1
能充分利用多 CPU
、多核环境下的硬件优点,使用多个 CPU
来缩短 Stop The World
的停顿时间。G1
能够不须要与其它收集器配合就能独立管理整个 GC堆
,根据 分代收集
的概念采用不一样的方式去处理。标记-整理
和 复制
算法,不会产生内存空间碎片。G1
能够创建可预测的停顿时间模型,将垃圾收集消耗的时间限制在必定的时间内。G1
之因此可以创建可预测的停顿时间模型,是由于它能够有计划的避免在整个 Java堆
中进行全区域的垃圾收集。G1
经过跟踪各个 Region
里面的内存堆积的价值大小(回收所得到的空间大小以及回收所需时间的经验值),在后台维护一个优先回收队列,每次根据容许的收集时间,优先回收价值最大的 Region
。这种使用 Region
划份内存空间以及有优先级的区域回收方式,保证了 G1
收集器在有限的时间内能够获取尽量高的收集效率。
在 G1
收集器中,Region
之间的对象引用以及其它收集器中的新生代与老年代之间的对象引用,虚拟机都是使用 Remembered Set
来避免全堆扫描的。G1
中的每个 Region
都有一个与之对应的 Remembered Set
,在对 Reference
类型的数据进行写操做的时间,虚拟机会产生一个屏障暂时中断写操做,而后检查这个引用的对象是否处于不一样的 Region
之中,若是是,就会经过 CardTable
把相关引用信息记录到被引用对象所属的 Region
的 Remembered Set
中。当进行内存回收时,在 GC Roots
的枚举范围内加入 Remembered Set
便可保证不对全堆扫描也不会有遗漏。
若是不计算维护 Remembered Set
的操做,G1
收集器的运行过程大体能够分为4个步骤:
初始标记阶段只是简单的标记一下 GC Roots
能直接关联到的对象,而且修改TAMS(Next Top At Mark Start)的值,让下一阶段用户程序并发运行时,能在正确可用的 Region
中建立新对象,这个阶段须要停顿线程,但耗时很短。并发标记阶段也是进行 GC Roots
的可达性分析过程,耗时很长可是可与用户程序一块儿工做。最终标记阶段是为了修正并发标记期间因用户线程继续运做而致使标记产生变更的那一部分对象的标记记录,虚拟机将这段时间对象变化记录在线程的 Remembered Set Logs
中,这个阶段须要把 Remembered Set Logs
中的数据合并到 Remembered Set
里,须要停顿线程,可是能够并行执行。 最后的筛选回收阶段会对 Region
的回收价值和成本进行排序,根据用户所指望的 GC
停顿时间来制定回收计划。
java -XX:+PrintCommandLineFlags -version
复制代码
在终端执行上述命令后,便可查看 JVM
所使用的收集器。
-XX:+UseParallelGC : 是虚拟机运行在 Server
模式下的默认值,打开此开关后,使用 Parallel Scavenge + Serial Old (PS MarkSweep)
的收集器组合进行内存回收。