Learn && Live
虚度年华浮萍于世,勤学善思至死不渝
Hey,欢迎阅读Connor学JVM系列,这个系列记录了我的JVM基础知识学习、复盘过程,欢迎各位大佬阅读斧正!原创不易,转载请注明出处:http://t.csdn.cn/WVqh7,话不多说我们马上开始!
垃圾收集器组合总结:
特点
(1)针对新生代的收集器,基于复制算法
(2)单线程收集,进行垃圾收集时必须暂停所有工作线程,Stop The World
应用场景
(1)依然是HotSpot在Client模式下默认的新生代收集器;
(2)优于其他收集器的地方: 简单高效(与其他收集器的单线程相比);
(3)对于限定单个CPU的环境来说,Serial收集器没有线程交互(切换)开销,可以获得最高的单线程收集效率;
(4)在用户的桌面应用场景中,可用内存一般不大(几十M至一两百M),可以在较短时间内完成垃圾收集(几十MS至一百多MS),只要不频繁发生,这是可以接受的
(5)可以通过参数-XX:+UseSerialGC 显式使用Serial收集器
特点
(1)针对新生代的收集器
(2)Serial收集器的多线程版本,除了使用多线程进行垃圾收集外,其余行为(控制参数、收集算法、回收策略等)和Serial完全一样
(3)新生代采用复制算法,老年代采用标记-整理算法
应用场景
(1)服务端模式下许多虚拟机首选的新生代收集器
(2)与作为老年代收集器的CMS搭配。ParNew收集器是激活CMS后的默认新生代收集器
(3)在单CPU环境下效率不如Serial收集器,因为线程之间的交互存在开销
使用参数
-XX:+UseConcMarkSweepGC:强制指定CMS激活后的默认收集器
-XX:ParallelGCThreads:指定垃圾收集的线程数,默认开启的收集线程数与CPU数量相同
特点
(1)针对新生代的收集器
(2)并行的多线程收集器
(2)关注吞吐量,吞吐量的计算:运行代码时间 / (运行代码时间 + 运行垃圾收集时间)
(3)采用复制算法
应用场景
高吞吐量可以最高效率地利用处理器资源,尽快完成程序的运算任务,主要适合后台运算而不需要过多交互的分析任务
使用参数
-XX:MaxGCPauseMillis:一个大于0的毫秒数,收集器将尽力保证内存回收时间不超过用户设定值。注意不要设置的太小,即让垃圾收集时间太短,这样做会导致垃圾收集更频繁,牺牲吞吐量和新生代空间
-XX:GCTimeRatio:设置一个正整数,表示用户期望虚拟机消耗在垃圾收集上的时间不超过程序运行时间的 1 / (1 + N),默认为99
-XX:+UseAdaptiveSizePolicy:开关参数,开启后开启垃圾收集的自适应调剂策略:虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整新生代大小、Eden与Survivor区的比例等参数,以提供最合适的停顿时间或最大的吞吐量
(1)Serial收集器的老年代版本,单线程收集器,基于标记 - 整理算法
(2)主要供客户端模式下的HotSpot虚拟机使用
(3)在服务端模式下可以有两种用途:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BFI1Jo22-1661218543319)(F:\yhy925\dailylife\Work\1.Java\JVM\Resources\3.垃圾收集器\8.Parallel Scavenge.png)]
(1)Parallel Scavenge收集器的老年代版本,支持多线程并行收集,基于标记-整理算法
(2)JDK6及之后用来替代Serial Old收集器
(3)在注重吞吐量或CPU资源较为稀缺的场合,优先考虑 Parallel Scavenge + Parallel Old组合
特点
(1)以获取最短回收停顿时间为目标的收集器,针对老年代,基于标记-清除算法,并发收集、低停顿
(2)适用于目前的互联网网站和基于浏览器的B/S系统的服务端上,提供尽可能短的系统停顿时间,提高服务的响应速度,改善交互体验
运作过程
(1)初始标记。标记GC Roots直接关联到的对象,速度很快
(2)并发标记。从GC Roots的直接关联对象开始遍历整个对象图的过程,这个过程耗时较长但不需要停顿用户线程,可以与垃圾收集线程一起并发运行
(3)重新标记。修正并发标记期间,因用户程序继续运行导致标记产生变动的那一部分对象的标记记录,停顿时间比初始标记阶段稍长,但远比并发标记阶段时间短
(4)并发清除。清除标记阶段判断的已经死亡的对象,因为不需要移动存活对象,可以与用户线程同时并发
缺点
1.对CPU资源非常敏感,并发阶段虽不会导致用户线程停顿,但会占用一部分线程导致应用程序变慢,降低吞吐量
(1)CMS默认启动的回收线程数是 (CPU数量 + 3) / 4
(2)如果CPU数多于四个,则回收线程数只占用不少于25%的CPU运算资源,随着CPU数量增加而下降
(3)如果CPU数不足四个,则可能会影响用户程序的运行效率,因为需要在CPU高负载的情况下再分出一部分运算能力执行收集器线程
2.无法处理浮动垃圾,有可能导致Concurrent Mode Failure失败
(1)浮动垃圾:在并发标记和并发清除阶段,收集线程和用户线程同时运行,这就会导致在清理的同时不断产生新的垃圾对象,而这些新的垃圾对象只能留到下一次垃圾收集时再清理
(2)同样因为垃圾收集与用户线程同时运行,需要预留足够内存空间给用户线程,因此CMS收集器不能等老年代几乎完全被填满了再收集,需要为老年代的内存空间设置一个阈值,大于这个比例后就需要开始垃圾收集
3.基于标记 - 清除算法可能导致收集结束后产生大量空间碎片,无法分配空间进而导致Full GC,可通过两个参数辅助解决(JDK9已废弃)
特点
(1)面向服务端的整堆收集器,JDK9之后的默认收集器
(2)并行与并发。G1能充分利用多CPU、多核环境下的硬件优势,使用多个CPU来缩短Stop The World停顿的时间,通过并发的方式让程序与垃圾收集同时执行
(3)分代收集。分代概念在 G1 中依然得以保留。虽然 G1 可以独立管理整个 GC 堆,但它能够采用不同的方式去处理新创建的对象和已经存活了一段时间、熬过多次 GC 的旧对象以获取更好的收集效果。
(4)空间整合。G1 从整体来看是基于“标记—整理”算法实现的收集器,从局部(两个 Region 之间)上来看是基于“复制”算法实现的,这两种算法都意味着 G1 运作期间不会产生内存空间碎片,收集后能提供规整的可用内存。这种特性有利于程序长时间运行,分配大对象时不会因为无法找到连续内存空间而提前触发下一次GC。
(5)可预测的停顿。 G1 除了追求低停顿外,还能建立可预测的停顿时间模型,能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒
分区设计
(1)G1放弃固定大小和数量的分代区域划分,而是把连续的Java堆划分为等大的独立空间Region,每一个Region都可以根据需要充当Eden、Survivor或老年代空间,收集器能够针对不同角色的Region采用不同的处理策略
(2)Region中还有一类特殊的 Humongous Region,专门用于存储大对象(大小超过一个Region容量的一半),而超过了整个Region容量的超大对象,将会被存放在N个连续的Humongous Region之中,G1的大多数行为都把Humongous Region作为老年代的一部分来看待
(3)每个Region的大小可以通过参数 -XX:G1HeapRegionSize 设定,取值范围为1MB - 32MB,且应为2的N次幂
为什么G1可以实现可预测的停顿时间模型
(1)将Region作为单次回收的最小单元,即每次收集到的内存空间都是Region大小的整数倍,避免整个Java堆中进行全区域的垃圾收集
(2)有计划地回收
TAMS
(1)保证垃圾收集线程和用户线程并发执行期间创建新对象的内存分配
(2)G1为每一个Region设计了两个名为TAMS(Top at Mark Start)的指针,把Region中的一部分空间划分出来用于并发回收过程中的新对象分配,并发回收时新分配的对象地址都必须在这两个指针位置以上,因为G1收集器默认在这个地址以上的对象都是被显式标记过的,即存活的
运行过程
(1)初始标记
(2)并发标记
(3)最终标记
(4)筛选回收
都十分关注停顿时间的控制
不同点:
(1)G1可以指定最大停顿时间、分Region的内存布局、按收益动态确定回收集
(2)G1从整体上看基于标记-整理算法,局部上看基于标记-复制算法;CMS基于标记-清除算法
(3)G1不会产生内存空间碎片,垃圾收集完成后能提供规整的可用内存