jvm-第四节垃圾回收器的细节实现
# 垃圾回收器串讲及 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发展中的变化,比如针对漏标部分的处理,针对跨代引用的处理;
-
安全点和安全区域的区别
不恋尘世浮华,不写红尘纷扰