垃圾收集算法:为实现垃圾回收提供理论支持
垃圾收集器:利用垃圾收集算法,实现垃圾回收的实践落地。
各种垃圾收集器之间也是可以配合使用的:
比如 CMS 可以和ParNew配合,CMS 和 Parallele Scavenge 不能使用。
下图中表示了各个垃圾收集器作用的范围,以及各个垃圾收集器之间可以配合使用的关系
Stop The World
简写为 STW,也叫全局停顿,Java代码停止运行,native 代码继续运行,但不能与JVM进行交互。 原因:多半由于垃圾回收导致;也可能是 Dump线程,死锁检查、 Dump 堆等导致。Stop The World 会导致服务停止,请求没有响应;主从切换,危害生产环境
并行收集 vs 并发收集并行收集:指多个垃圾收集线程并行工作,但是收集过程中,用户线程(你的业务线程)还是处于等待状态。
并发收集:指用户线程与垃圾收集线程同时工作
吞吐量- 吞吐量是指CPU用于运行用户代码的时间与CPU总消耗时间的比值。
- 计算公式:运行用户代码时间 / (运行用户代码时间 + 垃圾收集时间)。比如Jvm已经运行了80分钟,垃圾收集总共花费了1分钟,也就是 80/81
垃圾收集器 1. Serial 收集器
采用复制算法。是新生代的垃圾收集器。
- 是单线程的收集器。
- 收集过程全程 Stop The World。
- 适用于客户端程序,以 -client运行,默认就是使用 Serial。
- 适用于单核机器
Serial 收集器德多线程版本,除使用了多线程外,其余和 Serial收集器一样。包括:JVM参数,Stop The World 的表现,垃圾收集算法都是一样的。
- 多线程
- 可以使用 -XX:ParallelGCThreads 设置垃圾收集的线程数。一般设置成同CPU核心数就可以了。
- 主要用来和 CMS 配合使用
Parallele Scavenge 收集器 关注的是吞吐量。适用于注重吞吐量的场景
- 也叫做吞吐量优先收集器
- 采用复制算法
- 也是并行的多线程收集器,这一点和 ParNew类似
- Parallele Scavenge 的特点 :
- 可以达到一个可控制的吞吐量
- -XX:MaxGCPauseMillis : 控制最大的垃圾收集停顿时间(尽力)。比如设置100ms,垃圾收集每次时间尽量不超过100ms
- -XX:GCTimeRatis : 设置吞吐量的大小,取值0-100,系统花费不超过 1/(1+n) 的时间用于垃圾收集
- 自适应垃圾收集策略 : 可用 -XX:+UseAdptiveSizePolicy 打开。
- 打开自适应策略后,无需手动设置新生代的大小(-Xmn)、Eden与Survivor区的比例(-XX:SurvivorRatio)等参数。虚拟机会自动根据系统的运行状况收集性能监控信息,动态的调整这些参数,从而达到最优的停顿时间以及最高的吞吐量
- 可以达到一个可控制的吞吐量
Serial Old 收集器 是 Serial 的老年代版本。采用标记-整理算法。适用场景:
- 可以和Serial 、ParNew 、Parallel Scavenge 这三个新生代的垃圾收集器配合使用
- CMS收集器出现故障的时候,会用 Serial Old 作为后备
Parallel Old 是 Parallele Scavenge 的老年代版本。采用 标记-整理算法。
- 只能和 Parallele Scavenge 配合使用。所以适用场景也是关注吞吐量的场景
CMS :Concurrent Mark Sweep 。 并发收集器。使用 标记-清除算法。上文讲的都是串行、并行收集器。
1. 初始标记- 标记GC Roots能直接关联到的对象,会 Stop The World
- 找出所有GC Roots 能关联到的对象。并发执行,无 Stop The World
- 重新标记那些在并发标记阶段,引用被更新的对象,从而减少后面重新标记阶段的工作量。无 Stop The World
- 可使用 XX:-CMSPrecleaningEnabled 关闭并发预清理阶段,默认打开
- 和并发预清理做的事情一样,此阶段并发执行,无 Stop The World
- 当Eden的使用量大于CMSScheduleRemarkEdenSizeThreshold 的阈值(默认2M)时,才能执行该阶段
- 并发可中止的预清理阶段的主要作用是:允许我们能够控制预清理阶段的结束时机。比如扫描多长时间(CMSMaxAbortablePrecleanTime,默认5秒)或者 Eden 区使用占比达到一定的阈值(CMSScheduleRemarkEdenPenetration,默认50%)就结束本阶段
- 修正并发标记期间,因为用户程序继续执行,导致标记发生变动的那些对象的标记
- 一般来说,重新标记花费的时间会比初始标记阶段长一些,但比并发标记的时间短。
- 此阶段 会 Stop The World
- 基于标记结果,清除掉前面标记出来的垃圾。此阶段并发执行, 无 Stop The World
- 清理本次CMS GC的上下文信息,为下一次GC做准备
- Stop The World
- 大多过程并发执行
- CPU资源比较敏感,并发阶段可能导致应用吞吐量的降低
- 无法处理浮动垃圾。并发清理阶段业务还在运行,会产生新的垃圾,这部分的叫浮动垃圾
- 不能等到老年代几乎满了才开始收集。预留的内存不够 →引发了“Concurrent Mode Failure”问题 →使用“Serial Old”垃圾回收器作为后备
- 可使用 CMSInitiatingOccupancyFraction 设置老年代占比达到多少就触发垃圾收集器,默认是68%
- 内存碎片的问题。因为是使用标记-清除。
- XX:+UseCMSCompactAtFullCollection”,默认就打开了。意思是在Full GC之后要再次进行“Stop the World”,停止工作线程,然后进行碎片整理,就是把存活对象挪到一起,空出来大片连续内存空间,避免内存碎片。
- -XX:CMSFullGCsBeforeCompaction”,这个意思是执行多少次Full GC之后再执行一次内存碎片整理的工作,默认是0,意思就是每次Full GC之后都会进行一次内存整理。
CMS 收集器适用场景:希望体统停顿时间短,响应速度快的场景,比如各种服务器应用程序
G1 收集器G1 收集器 全称 Garbge First , 是面向服务器端的应用的垃圾收集器。G1 把内存划分为大小相等的 Region 。
通过参数:-XX:G1HeapRegionSize 指定Region的大小,取值范围 1 ~ 32 MB。一定要是2的N次幂。把大对象(超过 Regiony一半大小)放在 Humongous 中
它既可以用在新生代,也可以用在老年代。
G1 收集器 设计思想把内存区域分为若干个Region,然后区跟踪每一个 Region里面垃圾堆积的价值大小,若回收掉这个Region,能够获得多少剩余的空间,之后G1收集器会在后台构建一个优先列表,根据上面的价值大小,做了个排序。同时会根据设置的允许的收集时间,去优先回收价值高的Region。这样就可以获得一个更高的垃圾回收效率。



