jvm gc小结
注:图中有连线相连的,表示可以搭配使用,如新生代ParNew + 老年代CMS。
YoungGC = MinorGC:对新生代进行回收,在Eden区满的时候触发;
FullGC:新生代+老年代同时回收,即对整个堆进行回收,老年代满了会触发。
1、新生代收集器(Eden + S0 + S1,标记复制)
-
Serial
-
单线程版本,只有一个gc线程;
-
gc线程与用户线程串行执行,STW;
-
适用于:client模式下,虚拟机内存分配不大、单cpu环境时,减少切换开销,高效执行回收;
-
-
ParNew
-
多线程版本的serial收集器,策略等完全一样;
-
多个gc线程并行回收,专注于减少STW时长,提升响应速度;
-
更适合用于,与用户交互的程序;stw越短体验越好
-
-
Parallel Scavenge
-
多gc线程并行收集
-
自适应策略,自动调节新老代大小比例等参数,专注于可控制的吞吐量(吞吐量 = 运行用户代码时间 / (运行用户代码时间 + 垃圾收集时间))
-
更适用于非用户交互的后台计算程序等;
-
2、老年代收集器
-
Serial old
-
Serial 收集器的老年代版本;
-
适用于client模式下的老年代收集;
- 作为CMS收集器的后备预案,在并发收集发射Concurrent Mode Failure时使用; image.png
-
-
Parallel Old
-
Parallel Scavenge 的老年代版本;
-
多线程 + 标记整理算法;
-
与Parallel Scavenge(新生代回收)组合,实现【吞吐量优先】目标;
image.png
-
-
CMS
-
以实现最短STW时间为目的,适用于注重响应速度、用户体验的服务;
-
主要步骤:
image.png
-
初始标记:仅标记GC Roots能够关联的对象,STW时间很短;
-
并发标记:与用户线程并发执行,无STW,用于GC Roots Tracing的分析过程,耗时较长;
-
重新标记:用于修正并发标记期间由于用户线程同时执行导致标记变动的记录,STW时间较短,但比初始标记长;
-
并发清除:与用户线程同时进行,清除标记的垃圾;
-
-
存在的问题:
-
采用标记清除算法,产生碎片,导致频繁的FullGC,可以设置-XX:+UseCMSCompactAtFullCollection(默认开启),在FullGC时进行内存碎片整理;可以设置-XX:CMSFullGCsBeforeCompaction,标识执行多少次不带压缩的FullGC后执行一次带压缩的;
-
对cpu资源敏感,gc线程占用cpu资源导致吞吐量下降。默认启动线程数是 (CPU数量 + 3)/4,如果只有一两个cpu,则吞吐量将下降50%!!!
-
易产生“浮动垃圾”:由于并发清除阶段,用户线程在并发执行产生的新的垃圾得不到及时回收;用户线程的执行也需要预留足够的空间,如预留空间不够,则会出现Concurrent Mode Failure,只能使用Serial old收集器重新收集,导致STW更长!!!
-
-
-
G1(Garbage First)
-
多线程可以与用户线程并发执行;
- 不会产生碎片:基于region的设计,整体采用标记整理算法,局部两个region之间基于复制算法实现; image.png
-
可控可预测的STW时间:记录维护各个region的回收价值,优先收集回收价值高的region(只回收部分region,避免回收整个老年代)
-
主要步骤:
image.png
-
初始标记:类比CMS
-
并发标记:类比CMS
-
最终标记:类比CMS
-
筛选回收:不同于CMS,根据用户设定的允许收集时长,选取部分高回收价值的region,优先收集。
-
避免FullGC,可控STW时间
-
不牺牲吞吐性能
-
不会产生内存碎片,有利于长期运行;
-
-
-