垃圾收集器
垃圾收集算法,都是一个原理,这些算法的实现的最终结果,就是垃圾收集器。每个垃圾收集器虽然算法上类似,但是各个都有着自己的优势。如图:
这七个就是是如今比较流行的垃圾收集器。它们都是在分代收集算法的策略下运行的。
Serial收集器
这是一个最古老的垃圾收集器,现在几乎不被使用了。它的原理非常简单,就是在进行垃圾收集的时候暂停所有的线程。
正如图所示,这是一个单核的垃圾收集器,会在新生代使用复制算法,在老年代执行整理算法。一般在收集几十兆的新生代,所暂停的时间也仅仅在十几毫秒以内,对于运行在客户端模式下的虚拟机而言,也是可以接受的。
Serial Old收集器
Serial Old收集器是Serial收集器的老年版本。它经常被用来与其他收集器搭配使用。一般的搭档是 Parallel Scavenge收集器,还有一个就是作为CMS收集器发生失败时的后备预案。
ParNew收集器
ParNew收集器是Serial收集器的多线程版本。
遗憾的是ParNew收集器仅仅只有复制算法实现了多线程,在标记整理当中,还是需要Serial Old收集器,暂停所有的线程来进行回收内存。但垃圾收集器并不是只能使用一种类型,ParNew收集器还能和CMS收集器结合在一起,实现完全的多线程垃圾收集。
Parallel Scabenge和Parallel Old收集器
Parallel Scabenge和Parallel Old并不是同一时期的产物,是先有了Parallel Scabenge收集器,然后在JDK6的时候才提供了Parallel Old收集器,之后我们可以统称为Parallel收集器。运行效果如图:
Parallel收集器的特点和其他的收集都有着很大的不同,这个收集器不把目光局限于缩短线程停顿的时间,而是引入了一个新的名词:吞吐量。
吞吐量(Throughput = 运行用户代码时间 / (运行用户代码时间 + 垃圾收集时间))。
如果虚拟机完成某个任务,用户代码加上垃圾收集总共耗费了100分钟,其中垃圾收集花掉了一分钟,那么吞吐量就是99%。
可以通过 -XX:MaxGCPauseMills 参数设置内存回收花费最大时间, -XX:GCTimeRatio 设置垃圾收集时间占总时间的比率。-XX:+UseAdaptiveSizePolicy开启自动吞吐量控制。
作为一个吞吐量优先的收集器,虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整停顿时间。这就是 GC 的自适应调整策略(GC Ergonomics)。
JDK8用的正是这种模式的收集器。
CMS收集器
CMS收集器是一个基于标记清除算法的,能并发收集,低停顿的收集器。
这个收集器的运行过程更为复杂,整个过程分为四个阶段:
- 初始标记
- 并发标记
- 重新标记
- 并发清除
可惜的是这个收集器无法处理“浮动垃圾”,并且也可能会产生内存碎片过多的问题,目前并未广泛的投入使用。
G1收集器
G1收集器是在垃圾收集器技术发展史上的一个里程碑式的成果。G1的进行回收的标准不再是它属于哪个分代,而是哪块内存中存放的垃圾数量最大,回收收益最大,这就是G1的Mixed GC模式。
这个收集器开创了面向局部收集的设计思路和基于Region的内存布局形式,同样有着四个阶段:
- 初始标记:仅仅只是标记一下GC Roots能直接关联到的对象。
- 并发标记:开始进行可达性分析。
- 最终标记:处理并发阶段遗留的SATB记录。
- 筛选回收:对各个Region的价值和回收成本进行排序,然后回收。
就目前从JDK9到最新的JDK13而言,使用的正是G1收集器。这也是收集器未来的发展趋势。
shenandoah收集器
拥有九个阶段的、及其复杂的收集器,是基于G1的思想研发出来,目前处于试验状态。
ZGC收集器
引入的染色指针的概念,也是基于G1的思想,而且对并发整理算法有着特别的改进,是一个新的低延迟收集器,目前也处于试验状态。
Epsilon收集器
拥有自动内存管理子系统的收集器。不以垃圾回收为关注点,而是集中在内存管理方面,是一个在只需要运行数分钟就关闭的应用上,有着极其低延迟的收集器。
如何查看GC日志
我们在进行调优的时候,往往需要根据GC情况来进行,但是我们该怎么得知GC信息呢?
查看GC详细信息
在JDK9之前使用-XX:+PrintGCDetails查看GC日志
1 | //JDK8 |
在JDK9以及之后使用-Xlog:gc*查看GC日志
1 | //-Xlog:gc* |
查看GC前后堆
JDK9之前使用-XX:+PrintHeapAtGC
1 | {Heap before GC invocations=1 (full 0): |
在JDK9之后使用 -Xlog:gc+heap=debug
1 | [0.017s][info][gc,heap] Heap region size: 1M |
查看并发时间以及停顿时间
JDK9之前使用 -XX:+PrintGCApplicationConcurrentTime 或-XX:+PrintGCApplicationStoppedTime
1 | Application time: 0.0037062 seconds |
JDK9以及之后使用 -Xlog:safepoint
1 | [0.069s][info][safepoint] Safepoint "EnableBiasedLocking", Time since last: 42245400 ns, Reaching safepoint: 71800 ns, At safepoint: 47700 ns, Total: 119500 ns |