垃圾回收器串讲及 HostSpot 的细节实现
本篇知识点概况
- 并发标记与三色标记
- gc并发下漏标问题与不同垃圾回收期下的处理方案(G1,Cms对比)
- 跨代引用
- 安全点与安全区域
- gc参数(了解)
- 其他的垃圾回收期(了解)
并发标记与三色标记
- 三色标记诞生的历史:在三色标记之前有一个标记清除算法,根据可达性,可达设置为1,不可达设置为0,都完事之后统一清理,但是不能异步,所以stw时间较长,对于要求实时性的系统不可接受便有了可以异步的三色标记
- 三色标记的概念:三色分别是黑 灰 白,支持并发
- 黑色:跟对象,且它所有的引用都已经扫描
- 灰色:本身被扫描,但引用的对象没有扫描完
- 白色:未被扫描
gc并发下漏标问题与不同垃圾回收期下的处理方案(G1,Cms对比)
- 三色标记漏标问题:原因是并发扫描过程中,引用发生变化,以下面三张图为例
- 下面的图讲述扫描时引用发生了变化
- 如何解决这个漏标问题,下面分别是cms与g1中解决方法
- cms解决漏标之incremental update:当一个白色对象被一个黑色对象引用,将黑色标记为灰色,重新扫描;
- g1解决漏标之satb:stab既快照,当一个对象被修改后,会进行标记,然后颜色改成灰色,并在下次回收的时候进行处理,标记为黑色
跨代引用
- 跨代引用的问题:堆分为新生代,老年代,如果老年代对象引用了新生代对象,新生代回收就要扫描整个老年代,开销太大,
- 解决方法1-记忆集:rset,相当于一个位图记录,新生代,老年代之间的引用关系,可以避免扫描整个老年代
- 解决方法2-cardTable:是一种记录堆内存区域是否被修改的数据结构,按页划分表格,记录被修改的页,垃圾回收时只扫描dirty的页,避免全盘扫描
安全点与安全区域
- 安全点作用:所有线程进入安全点,用户线程暂停,gc线程开始工作
- 什么是安全点:比如方法调用,循环跳转,异常跳转,一般这些指令才会产生安全点,用户线程在执行过程中会不断轮训这个安全点,如果发现为true就在最近的安全点上主动挂起
- 安全区域的作用:所有线程进入安全点,用户线程暂停,gc线程开始工作;代码在这段区域中对象引用关系不会发生变化;其次是如果线程一直sleep,block,程序是无法进入安全点的,
- 什么是安全区域:举个例子 sychronized
private static Selector selector;
private static void processRequests() {
// 进入安全区域
synchronized(selector) {
// 在安全区域内进行 I/O 操作
selector.select();
// 处理 I/O 事件
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
while(keyIterator.hasNext()) {
SelectionKey key = keyIterator.next();
if(key.isAcceptable()) {
// 处理连接请求
} else if (key.isReadable()) {
// 处理读事件
} else if (key.isWritable()) {
// 处理写事件
}
keyIterator.remove();
}
}
// 离开安全区域,进行其他计算
// ...
}
gc参数(了解)
- 上面是一条gc日志
- gc常用参数
GC 常用参数
-Xmn -Xms -Xmx –Xss 年轻代 最小堆 最大堆 栈空间
-XX:+UseTLAB 使用 TLAB,默认打开
-XX:+PrintTLAB 打印 TLAB 的使用情况
-XX:TLABSize 设置 TLAB 大小
-XX:+DisableExplicitGC 启用用于禁用对的调用处理的选项 System.gc() -XX:+PrintGC 查看 GC 基本信息
-XX:+PrintGCDetails 查看 GC 详细信息
-XX:+PrintHeapAtGC 每次一次 GC 后,都打印堆信息
-XX:+PrintGCTimeStamps 启用在每个 GC 上打印时间戳的功能
-XX:+PrintGCApplicationConcurrentTime 打印应用程序时间(低) -XX:+PrintGCApplicationStoppedTime 打印暂停时长(低)
-XX:+PrintReferenceGC 记录回收了多少种不同引用类型的引用(重要性低)
-verbose:class 类加载详细过程
-XX:+PrintVMOptions 可在程序运行时,打印虚拟机接受到的命令行显示参数
-XX:+PrintFlagsFinal -XX:+PrintFlagsInitial 打印所有的 JVM 参数、查看所有 JVM 参数启动的初始值(必须会用)
-XX:MaxTenuringThreshold 升代年龄,最大值 15, 并行(吞吐量)收集器的默认值为 15,而 CMS 收集器的默认值为 6。 Parallel 常用参数
-XX:SurvivorRatio 设置伊甸园空间大小与幸存者空间大小之间的比率。默认情况下,此选项设置为 8
-XX:PreTenureSizeThreshold 大对象到底多大,大于这个值的参数直接在老年代分配
-XX:MaxTenuringThreshold 升代年龄,最大值 15, 并行(吞吐量)收集器的默认值为 15,而 CMS 收集器的默认值为 6。
-XX:+ParallelGCThreads 并行收集器的线程数,同样适用于 CMS,一般设为和 CPU 核数相同
-XX:+UseAdaptiveSizePolicy 自动选择各区大小比例
CMS 常用参数
-XX:+UseConcMarkSweepGC 启用 CMS 垃圾回收器
-XX:+ParallelGCThreads 并行收集器的线程数,同样适用于 CMS,一般设为和 CPU 核数相同
其他的垃圾回收器(了解)
- 传统的垃圾回收期:内存占用,吞吐量,延时只能满足俩,而 现在延时这个指标越来越重要,就有了低延迟垃圾回收器
Eplison(了解即可)
这个垃圾回收器不能进行垃圾回收,是一个“不干活”的垃圾回收器,由 RedHat 退出,它还要负责堆的管理与布局、对象的分配、与解释器
的协作、与编译器的协作、与监控子系统协作等职责,主要用于需要剥离垃圾收集器影响的性能测试和压力测试。
ZGC(了解即可)
有类似于 G1 的 Region,但是没有分代。
标志性的设计是染色指针 ColoredPointers(这个概念了解即可),染色指针有 4TB 的内存限制,但是效率极高,它是一种将少量额外的信息存储在指针上
的技术。
它可以做到几乎整个收集过程全程可并发,短暂的 STW 也只与 GC Roots 大小相关而与堆空间内存大小无关,因此考科一实现任何堆空间 STW 的时间小于
十毫秒的目标。
Shenandoah(了解即可)
第一款非 Oracle 公司开发的垃圾回收器,有类似于 G1 的 Region,但是没有分代。
也用到了染色指针 ColoredPointers。
效率没有 ZGC 高,大概几十毫秒的目标
问题
- 垃圾回收器 从cms到g1发展中的变化,比如针对漏标部分的处理,针对跨代引用的处理;
- 安全点和安全区域的区别