CMS以流水线方式拆分了收集周期 , 将耗时长的操作单元保持与应用线程并发执行 。只将那些必需STW才能执行的操作单元单独拎出来 , 控制这些单元在恰当的时机运行 , 并能保证仅需短暂的时间就可以完成 。这样 , 在整个收集周期内 , 只有 两次短暂的暂停(初始标记和重新标记) , 达到了近似并发的目的 。CMS收集器优点:并发收集、低停顿 。
CMS收集器缺点:
- CMS收集器对CPU资源非常敏感 。
- CMS收集器无法处理浮动垃圾(Floating Garbage) , 所以如果采用CMS算法 , JVM还是在浮动垃圾很多时 , 自动运行fullgc一次来清除浮动垃圾 。
- CMS收集器是基于标记-清除算法 , 该算法的缺点都有 。
(1)响应时间优先 , 能接受牺牲一定的吞吐量 , 如果需要高响应时间和高吞吐量 , 推荐使用G1 。后续文章再继续介绍G1 。G1也是JDK9默认的垃圾收集器;
(2)硬件配置较高 , 即CPU和内存资源充足 。CMS由于需要与用户线程并发执行 , 所以可能会竞争CPU资源 。同时CMS并发标记阶段 , 用户线程同时执行时会新建对象 , 故内存占用会比较高;
(3)堆大小在3G到8G之间 , 同时存活时间较长的对象比较多
下面再简单讲讲G1算法 ,
G1重新定义了堆空间 , 打破了原有的分代模型 , 将堆划分为一个个区域 。这么做的目的是在进行收集时不必在全堆范围内进行 , 这是它最显著的特点 。区域划分的好处就是带来了停顿时间可预测的收集模型:用户可以指定收集操作在多长时间内完成 。即G1提供了接近实时的收集特性 。
G1收集器将整个Java堆划分为多个大小相等的独立区域(Region) , 虽然还保留有新生代和老年代的概念 , 但新生代和老年代不再是物理隔离的了 , 它们都是一部分Region(不需要连续)的集合 。Region的大小是一致的 , 数值是在1M到32M字节之间的一个2的幂值数 , JVM会尽量划分2048个左右、同等大小的Region 。其实这个数字既可以手动调整 , G1也会根据堆大小自动进行调整 。
G1收集的运作过程大致如下:
- 初始标记(Initial Marking):仅仅只是标记一下GC Roots能直接关联到的对象 , 并且修改TAMS(Next Top at Mark Start)的值 , 让下一阶段用户程序并发运行时 , 能在正确可用的Region中创建新对象 , 这阶段需要停顿线程 , 但耗时很短 。
- 并发标记(Concurrent Marking):是从GC Roots开始堆中对象进行可达性分析 , 找出存活的对象 , 这阶段耗时较长 , 但可与用户程序并发执行 。
- 最终标记(Final Marking):是为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分标记记录 , 虚拟机将这段时间对象变化记录在线程Remembered Set Logs里面 , 最终标记阶段需要把Remembered Set Logs的数据合并到Remembered Set中 , 这阶段需要停顿线程 , 但是可并行执行 。
- 筛选回收(Live Data Counting and Evacuation):首先对各个Region的回收价值和成本进行排序 , 根据用户所期望的GC停顿时间来制定回收计划 。这个阶段也可以做到与用户程序一起并发执行 , 但是因为只回收一部分Region , 时间是用户可控制的 , 而且停顿用户线程将大幅提高收集效率 。
- 下图就是G1堆空间分布

文章插图
G1特点:
- 并行与并发:G1能充分利用多CPU、多核环境下的硬件优势 , 使用多个CPU来缩短Stop-the-world停顿的时间 , 部分其他收集器原来需要停顿Java线程执行的GC操作 , G1收集器仍然可以通过并发的方式让Java程序继续运行 。
- 分代收集
- 空间整合:与CMS的标记-清除算法不同 , G1从整体来看是基于标记-整理算法实现的收集器 , 从局部(两个Region之间)上来看是基于“复制”算法实现的 。但无论如何 , 这两种算法都意味着G1运作期间不会产生内存空间碎片 , 收集后能提供规整的可用内存 。这种特性有利于程序长时间运行 , 分配大对象时不会因为无法找到连续内存空间而提前触发下一次GC 。
推荐阅读
- 为什么Java中的const关键字没有实现?
- java大文件分片上传、断点续传、急速秒传
- 内网信息收集清单
- JavaScript 内置对象之——Date,看完你会更清晰
- Java自定义DNS解析器负载均衡实现
- 在微控制器平台等小型物联网设备上运行 JavaScript
- Java 字节码技术详解
- 垃圾发电原理及特点介绍
- Java,OpenCV,图像阈值分割,阈值化,二值阈值化、截断阈值化等
- Java 日志记录—记录什么和不记录什么?
