垃圾收集器的选择
如果你想要最小化地使用内存和并行开销,请选 serial GC
如果你想要最大化应用程序的吞吐量,请选Parallel GC
如果你想要最小化GC的中断或停顿时间,请选 CMS GC.
CMS
使用标记-清除算法。
初始标记阶段:标记出GC Roots能直接关联到的对象。(需要stop the world)
并发标记阶段:从GC Roots直接关联的对象开始遍历并标记整个对象图,这个过程耗时长,但是不需要暂停用户线程。
重新标记阶段:修正并发标记阶段,因用户程序继续运行而导致的标记产生变动的那一部分对象的标记记录,一般变动不多,因此耗时也不算长。(时间比初始标记长,比并发标记短,也需要stop the world)
并发清除阶段:清理删除标记阶段判断死亡的对象,释放内存空间。
可以作为GC Roots的对象:
- 虚拟机栈引用指向的对象
- 方法区中类静态属性指向的对象
- 方法区中常量引用的对象
- 本地方法中引用的对象
优势:并发收集,低延迟。
弊端:
会产生内存碎片。
CMS收集器对CPU资源非常敏感。
CMS无法处理浮动垃圾。
jdk9被标记为deprecate,意味着为了会被废弃,jdk14移除了CMS。
G1
官方给G1设定的目标是在延迟可控的情况下获得尽可能高的吞吐量,所以才担当起“全功能收集器”的重任与期望。
G1使用分区算法:
分代收集
G1使用分代型垃圾收集器,依旧区分新生代,老年代,新生代依旧有eden区和survivor区。但是不要求整个区都是连续的,也不再坚持固定大小和固定数量。
堆空间分成若干个区域,这些区域包括逻辑上的年轻代和老年代。也就是说同一个区域,在某些时候它可能是年轻代,某些时候可能是老年代。
使用:
开启G1垃圾收集器。
设置堆最大内存。
设置最大停顿时间。
适用于面向服务端应用,具有大内存,多处理器的机器。
什么时候推荐使用:
- 实时数据占用超过一半的堆空间
- 对象分配或者晋升的速度变化大
- 希望消除长时间的GC停顿
G1和CMS比较:
- CMS使用标记-清除算法,会产生内存碎片,而G1采用标记-整理算法,不会产生内存碎片。
- CMS只作用于老年代,需要配合parNew GC使用,而G1既可以作用于老年代,也可以作用于年轻代。不需要结合其他垃圾收集器。
- CMS收集器时以最小的停顿时间为目标的收集器,而G1收集器的是可预测垃圾回收的停顿时间
- CMS在小内存应用上表现更好,而G1在大内存应用上表现更佳,平衡点在6-8GB。