上一节:《JVM之GC算法》 知道GC算法的理论基础,咱们来看看具体的实现。只有落地的理论,才是真理。html
JVM虚拟机规范对垃圾收集器应该如何实现没有规定,由于没有最好的垃圾收集器,只有最适合的场景。算法
图中展现了7种做用于不一样分代的收集器,若是两个收集器之间存在连线,则说明它们能够搭配使用。虚拟机所处的区域则表示它是属于新生代仍是老年代收集器。多线程
7种:serial收集器、parnew收集器、parallel scavenge收集器、serial old 收集器、parallel old收集器、cms收集器、g1收集器(整堆收集器)、闭包
串行收集:单垃圾收集线程,进行收集工做,用户进程须要等待并发
并行收集:工做原理与串行同样,只是在收集垃圾时是多条线程同时进行,收集的效率在通常状况下天然高于单线程。性能
并发收集:指用户线程与垃圾收集线程同时工做(并发:同一时间间隔)。用户程序在继续运行,而垃圾收集程序运行在另外一个CPU上。spa
吞吐量:吞吐量就是CPU中用于运行用户代码的时间与CPU总消耗时间的比值(吞吐量 = 运行用户代码时间 / (运行用户代码时间 + 垃圾收集时间))线程
一、Serial收集器
Serial(串行)收集器:最基本,最古老的收集器,只有一个线程进行垃圾收集器的工做,而且在进行垃圾收集工做时须要暂停其余工做线程(stop the word),直到他工做结束;
Serial收集器简单高效,工做时没有线程交互的开销,因此能够得到很高的单线程收集效率,对于运行在Client模式下的虚拟机来讲很适合。htm
"-XX:+UseSerialGC":添加该参数来显式的使用Serial垃圾收集器。对象
二、Serial Old收集器
Serial Old收集器是Seria收集器的老年代版本,他一样是一个单线程收集器,使用" 标记-整理" 算法。
Serial Old收集器主要用于Client模式下的虚拟机使用。
Server模式下的两大用途:
三、ParNew 收集器
ParNew(并行)收集器就是Serial收集器的多线程版本,除了在收集垃圾时是启用多线程并行执行,其余行为(控制参数、收集算法、回收策略/Stop The Word、对象分配规则)彻底同样
应用场景:ParNew收集器是许多运行在Server模式下的虚拟机中首选的新生代收集器,由于它是除了Serial收集器外,惟一一个能与CMS收集器配合工做的。
"-XX:+UseConcMarkSweepGC":指定使用CMS后,会默认使用ParNew做为新生代收集器。
"-XX:+UseParNewGC":强制指定使用ParNew。
"-XX:ParallelGCThreads":指定垃圾收集的线程数量,ParNew默认开启的收集线程与CPU的数量相同。
四、Parallel Scavenge收集器
Parallel Scavenge收集器 相似于 ParNew 收集器, Parallel Scavenge收集器 更加关注吞吐量(高效的CPU利用率)。CMS等垃圾收集器关注更多的是用户线程的停顿时间(提搞用户体验);Parallel Scavenge 收集器提供不少参数供咱们找到最合适的停顿时间或者最大吞吐量。JDK1.8 默认的方式;
Parallel Scavenge收集器提供了两个参数来用于精确控制吞吐量,一是控制最大垃圾收集停顿时间的 -XX:MaxGCPauseMillis参数,二是控制吞吐量大小的 -XX:GCTimeRatio参数;
应用场景:注重高吞吐量以及CPU资源敏感的场合,均可以优先考虑Parallel Scavenge+Parallel Old 收集器。
五、Paraller Old收集器
Parallel Old收集器是Parallel Scavenge收集器的老年代版本,使用多线程和“标记-整理”算法。
在JDK1.6中才出现。
六、CMS(Conturrent Mark Sweep)收集器
CMS收集器是一种以获取最短回收停顿时间为目标的收集器。CMS收集器是基于“标记-清除”算法实现,它的整个运行过程能够分为:
CMS收集器运行的整个过程当中,最耗费时间的是并发标记和并发清除,GC收集器线程和用户线程是一块儿工做的,因此整体来讲,CMS收集器的内存回收过程是与用户线程一块儿并发执行的。
优势:并发收集、低停顿。
缺点:
七、G1(Garbage-First)收集器
G1的内存模型
G1收集器没有新生代和老年代的概念,而是将Java堆划分为一块块独立的大小相等的Region。当要进行垃圾收集时,首先估计每一个Region中的垃圾数量,每次都从垃圾回收价值最大的Region开始回收,所以能够得到最大的回收效率
Humongous是特殊的Old类型,专门放置大型对象.这样的划分方式意味着不须要一个连续的内存空间管理对象.G1将空间分为多个区域,优先回收垃圾最多的区域.
G1采用的是Mark-Copy ,有很是好的空间整合能力,不会产生大量的空间碎片
G1的一大优点在于可预测的停顿时间,可以尽量快地在指定时间内完成垃圾回收任务,在JDK11中,已经将G1设为默认垃圾回收器,经过jstat命令能够查看垃圾回收状况,在YGC时S0/S1并不会交换.
一个对象和它内部所引用的对象可能不在同一个Region中,那么当垃圾回收时,是否须要扫描整个堆内存才能完整地进行一次可达性分析?
固然不是,每一个Region都有一个Remembered Set,用于记录本区域中全部对象引用的对象所在的区域,从而在进行可达性分析时,只要在GC Roots中再加上Remembered Set便可防止对全部堆内存的遍历.
回收步骤
初始标记:标记与GC Roots直接关联的对象,中止全部用户线程,只启动一条初始标记线程,这个过程很快.
并发标记:进行全面的可达性分析,开启一条并发标记线程与用户线程并行执行.这个过程比较长.
最终标记:标记出并发标记过程当中用户线程新产生的垃圾.中止全部用户线程,并使用多条最终标记线程并行执行.
筛选回收:回收废弃的对象.此时也须要中止一切用户线程,并使用多条筛选回收线程并行执行.
G1为何能创建可预测的停顿时间模型?
由于它有计划的避免在整个Java堆中进行全区域的垃圾收集。G1跟踪各个Region里面的垃圾堆积的大小,在后台维护一个优先列表,每次根据容许的收集时间,优先回收价值最大的Region。这样就保证了在有限的时间内能够获取尽量高的收集效率。
G1与其余收集器的区别?
其余收集器的工做范围是整个新生代或者老年代、G1收集器的工做范围是整个Java堆。在使用G1收集器时,它将整个Java堆划分为多个大小相等的独立区域(Region)。虽然也保留了新生代、老年代的概念,但新生代和老年代再也不是相互隔离的,他们都是一部分Region(不须要连续)的集合。
一、单CPU或者小内存,单机程序 — -XX:+UseSerialGC
二、多CPU,须要大吞吐量,如后台计算型应用,容许工做线程停顿超过1秒 -XX:+UseParallelGC + -XX:+UseParallelOldGC
三、多CPU,追求低停顿时间,快速响应如互联网应用 -XX:+UseParNewGC + -XX:+UseConcMarkSweepGC
四、JVM本身选择
五、官方推荐G1,高性能