3. JVM GC算法及具体垃圾收集器( 三 )


若GC运行的时间少,并不会加快,反而说明清理空间少,那么GC会更频繁
3.5.6 CMS收集器
解决GC时产生的STW导致服务不可用
CMS( Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器 。目前很大一部分的Java应用集中在互联网网站或者基于浏览器的B/S系统的服务端上,这类应用通常都会较为关注服务的响应速度,希望系统停顿时间尽可能短,以给用户带来良好的交互体验 。CMS收集器就非常符合这类应用的需求 。
分为四个步骤
初始标记
寻找GC Roots
并发标记
时间长但是可与用户线程并发执行
通过三色算法,主要的思想就是在标记的过程中一旦对象的引用发生改变则记录下来,标记完成后发现还有问题就从对象引用关系变化处重新搜索标记
重新标记
解决并发标记阶段由并发执行用户线程产生的引用变化问题
并发清除
由于最耗时的两个阶段与用户线程并发执行,所以总体而言可看作与用户线程并发执行的收集器 。

3. JVM GC算法及具体垃圾收集器

文章插图
CMS默认启动的回收线程数是(处理器核心数量+3)/4,也就是说,如果处理器核心数在四个或以上,并发回收时垃圾收集线程只占用不超过25%的处理器运算资源,并且会随着处理器核心数量的增加而下降 。
但CMS堆CPU的要求高,核心数少说明处理线程能力弱,多线程带来的切换负担增加反而可能降低性能 。
由于采用标记-清理 算法 所以没有连续空间分配对象内存的时候会产生Full GC 并且是带着整理的,这段对象移动产生的消耗无法变短 。(/ZGC 可进行并发移动对象)
CMS默认启动的回收线程数是(处理器核心数量+3)/4,也就是说,如果处理器核心数在四个或以上
3.5.7First 收集器
基于的内存布局与管理 。
JDK9后G1是默认收集器取代PS+PO 。
JDK10后进行实现解耦,抽取接口实现与抽象分离从而方便编译器的扩展与替换也进一步替换CMS 。
G1将内存划分为一个个区域,区域又被标记为新生代(Eden、)、老年代。
跨代引用问题,需要采用双向卡表结构来解决,额外消耗内存大约10%-20%左右的内存用户解决跨代引用问题 。
并发运行问题
CMS通过增量更新G1采用原始快照SATB
相比起增量更新算法,原始快照搜索能够减少并发标记和重新标记阶段的消耗,避免CMS那样在最终标记阶段停顿时间过长的缺点,但是在用户程序运行过程中确实会产生由跟踪引用变化带来的额外负担 。
运行过程
初始标记
与同步进行,实际不消耗时间
并发标记
最终标记
SWT处理SATB
筛选回收
存活对象移动到空的再整体清空,但可根据用户指定的期望时间来定制回收计划 。
并发收集器选择
按照笔者的实践经验,目前在小内存应用上CMS的表现大概率仍然要会优于G1,而在大内存应用上G1则大多能发挥其优势,这个优劣势的Java堆容量平衡点通常在6GB至8GB之间,当然,以上这些也仅是经验之谈,不同应用需要量体裁衣地实际测试才能得出最合适的结论,随着的开发者对G1的不断优化,也会让对比结果继续向G1倾斜 。
G1的跨代引用问题更严重,内存集需维护双向卡表结构 。占用内存更多
3.6低延迟垃圾收集器
衡量垃圾收集器的指标
硬件提升 内存扩大 提高吞吐量 要被回收的内存也更多,将提高延迟通过三色标记算法并发执行GC以及用户线程从而提高效率
CMS会带来内存碎片问题从而STW G1虽然通过粒度细化减少停顿但毕竟还是有停顿