网站建设 工作室,建筑网站设计模版,网站 按钮 素材,备案号查询平台G1(并发)
G1 特点
G1#xff08;Garbage-First#xff09;是一款面向服务端应用的垃圾收集器#xff0c;应用于新生代和老年代、采用标记-整理算法、软实时、低延迟、可设定目标#xff08;最大 STW 停顿时间#xff09;的垃圾回收器#xff0c;用于代替 CMS#xff0…G1(并发)
G1 特点
G1Garbage-First是一款面向服务端应用的垃圾收集器应用于新生代和老年代、采用标记-整理算法、软实时、低延迟、可设定目标最大 STW 停顿时间的垃圾回收器用于代替 CMS适用于较大的堆4 ~ 6G在 JDK9 之后默认使用 G1
G1 对比其他处理器的优点 并发与并行 并行性G1 在回收期间可以有多个 GC 线程同时工作有效利用多核计算能力此时用户线程 STW 并发性G1 拥有与应用程序交替执行的能力部分工作可以和应用程序同时执行因此不会在整个回收阶段发生完全阻塞应用程序的情况 其他的垃圾收集器使用内置的 JVM 线程执行 GC 的多线程操作而 G1 GC 可以采用应用线程承担后台运行的 GC 工作JVM 的 GC 线程处理速度慢时系统会调用应用程序线程加速垃圾回收过程 分区算法 从分代上看G1 属于分代型垃圾回收器区分年轻代和老年代年轻代依然有 Eden 区和 Survivor 区。从堆结构上看新生代和老年代不再物理隔离不用担心每个代内存是否足够这种特性有利于程序长时间运行分配大对象时不会因为无法找到连续内存空间而提前触发下一次 GC 将整个堆划分成约 2048 个大小相同的独立 Region 块每个 Region 块大小根据堆空间的实际大小而定整体被控制在 1MB 到 32 MB之间且为 2 的 N 次幂所有 Region 大小相同在 JVM 生命周期内不会被改变。G1 把堆划分成多个大小相等的独立区域使得每个小空间可以单独进行垃圾回收 新的区域 Humongous本身属于老年代区当出现了一个巨型对象超出了分区容量的一半该对象就会进入到该区域。如果一个 H 区装不下一个巨型对象那么 G1 会寻找连续的 H 分区来存储为了能找到连续的 H 区有时候不得不启动 Full GC G1 不会对巨型对象进行拷贝回收时被优先考虑G1 会跟踪老年代所有 incoming 引用这样老年代 incoming 引用为 0 的巨型对象就可以在新生代垃圾回收时处理掉 Region 结构图 空间整合 CMS标记-清除算法、内存碎片、若干次 GC 后进行一次碎片整理 G1整体来看是基于标记 - 整理算法实现的收集器从局部Region 之间上来看是基于复制算法实现的两种算法都可以避免内存碎片 可预测的停顿时间模型软实时 soft real-time可以指定在 M 毫秒的时间片段内消耗在 GC 上的时间不得超过 N 毫秒 由于分块的原因G1 可以只选取部分区域进行内存回收这样缩小了回收的范围对于全局停顿情况也能得到较好的控制 G1 跟踪各个 Region 里面的垃圾堆积的价值大小回收所获得的空间大小以及回收所需时间通过过去回收的经验获得在后台维护一个优先列表每次根据允许的收集时间优先回收价值最大的 Region保证了 G1 收集器在有限的时间内可以获取尽可能高的收集效率 相比于 CMS GCG1 未必能做到 CMS 在最好情况下的延时停顿但是最差情况要好很多
G1 垃圾收集器的缺点 相较于 CMSG1 还不具备全方位、压倒性优势。比如在用户程序运行过程中G1 无论是为了垃圾收集产生的内存占用还是程序运行时的额外执行负载都要比 CMS 要高 从经验上来说在小内存应用上 CMS 的表现大概率会优于 G1而 G1 在大内存应用上则发挥其优势平衡点在 6-8GB 之间
应用场景 面向服务端应用针对具有大内存、多处理器的机器 需要低 GC 延迟并具有大堆的应用程序提供解决方案 记忆集
记忆集 Remembered Set 在新生代中每个 Region 都有一个 Remembered Set用来被哪些其他 Region 里的对象引用谁引用了我就记录谁 程序对 Reference 类型数据写操作时产生一个 Write Barrier 暂时中断操作检查该对象和 Reference 类型数据是否在不同的 Region跨代引用不同就将相关引用信息记录到 Reference 类型所属的 Region 的 Remembered Set 之中 进行内存回收时在 GC 根节点的枚举范围中加入 Remembered Set 即可保证不对全堆扫描也不会有遗漏
垃圾收集器在新生代中建立了记忆集这样的数据结构可以理解为它是一个抽象类具体实现记忆集的三种方式 字长精度 对象精度 卡精度(卡表)
卡表Card Table在老年代中是一种对记忆集的具体实现主要定义了记忆集的记录精度、与堆内存的映射关系等卡表中的每一个元素都对应着一块特定大小的内存块这个内存块称之为卡页card page当存在跨代引用时会将卡页标记为 dirtyJVM 对于卡页的维护也是通过写屏障的方式
收集集合 CSet 代表每次 GC 暂停时回收的一系列目标分区在任意一次收集暂停中CSet 所有分区都会被释放内部存活的对象都会被转移到分配的空闲分区中。年轻代收集 CSet 只容纳年轻代分区而混合收集会通过启发式算法在老年代候选回收分区中筛选出回收收益最高的分区添加到 CSet 中
卡表和操作系统内存页一个道理 CSet of Young Collection CSet of Mix Collection 工作原理
G1 中提供了三种垃圾回收模式YoungGC、Mixed GC 和 Full GC在不同的条件下被触发 当堆内存使用达到一定值默认 45%时开始老年代并发标记过程 标记完成马上开始混合回收过程 顺时针Young GC → Young GC Concurrent Mark → Mixed GC 顺序进行垃圾回收 Young GC发生在年轻代的 GC 算法一般对象除了巨型对象都是在 eden region 中分配内存当所有 eden region 被耗尽无法申请内存时就会触发一次 Young GCG1 停止应用程序的执行 STW把活跃对象放入老年代垃圾对象回收 回收过程 扫描根根引用连同 RSet 记录的外部引用作为扫描存活对象的入口 更新 RSet处理 dirty card queue 更新 RS此后 RSet 准确的反映对象的引用关系 dirty card queue类似缓存产生了引用先记录在这里然后更新到 RSet 作用产生引用直接更新 RSet 需要线程同步开销很大使用队列性能好 处理 RSet识别被老年代对象指向的 Eden 中的对象这些被指向的对象被认为是存活的对象把需要回收的分区放入 Young CSet 中进行回收 复制对象Eden 区内存段中存活的对象会被复制到 survivor 区survivor 区内存段中存活的对象如果年龄未达阈值年龄会加1达到阀值会被会被复制到 old 区中空的内存分段如果 survivor 空间不够Eden 空间的部分数据会直接晋升到老年代空间 处理引用处理 SoftWeakPhantomJNI Weak 等引用最终 Eden 空间的数据为空GC 停止工作 Concurrent Mark 初始标记标记从根节点直接可达的对象这个阶段是 STW 的并且会触发一次年轻代 GC 并发标记 (Concurrent Marking)在整个堆中进行并发标记应用程序并发执行可能被 YoungGC 中断。会计算每个区域的对象活性即区域中存活对象的比例若区域中的所有对象都是垃圾则这个区域会被立即回收实时回收给浮动垃圾准备出更多的空间把需要收集的 Region 放入 CSet 当中 最终标记为了修正在并发标记期间因用户程序继续运作而导致标记产生变动的那一部分标记记录虚拟机将这段时间对象变化记录在线程的 Remembered Set Logs 里面最终标记阶段需要把 Remembered Set Logs 的数据合并到 Remembered Set 中这阶段需要停顿线程但是可并行执行防止漏标 筛选回收并发清理阶段首先对 CSet 中各个 Region 中的回收价值和成本进行排序根据用户所期望的 GC 停顿时间来制定回收计划也需要 STW Mixed GC当很多对象晋升到老年代时为了避免堆内存被耗尽虚拟机会触发一个混合的垃圾收集器即 Mixed GC除了回收整个 young region还会回收一部分的 old region过程同 YGC 注意是一部分老年代而不是全部老年代可以选择哪些老年代 region 收集对垃圾回收的时间进行控制 在 G1 中Mixed GC 可以通过 -XX:InitiatingHeapOccupancyPercent 设置阈值 Full GC对象内存分配速度过快Mixed GC 来不及回收导致老年代被填满就会触发一次 Full GCG1 的 Full GC 算法就是单线程执行的垃圾回收会导致异常长时间的暂停时间需要进行不断的调优尽可能的避免 Full GC 产生 Full GC 的原因 晋升时没有足够的空间存放晋升的对象 并发处理过程完成之前空间耗尽浮动垃圾 相关参数 -XX:UseG1GC手动指定使用 G1 垃圾收集器执行内存回收任务 -XX:G1HeapRegionSize设置每个 Region 的大小。值是 2 的幂范围是 1MB 到 32MB 之间目标是根据最小的 Java 堆大小划分出约 2048 个区域默认是堆内存的 1/2000 -XX:MaxGCPauseMillis设置期望达到的最大 GC 停顿时间指标JVM会尽力实现但不保证达到默认值是 200ms -XX:ParallelGcThread设置 STW 时 GC 线程数的值最多设置为 8 -XX:ConcGCThreads设置并发标记线程数设置为并行垃圾回收线程数 ParallelGcThreads 的1/4左右 -XX:InitiatingHeapoccupancyPercent设置触发并发 Mixed GC 周期的 Java 堆占用率阈值超过此值就触发 GC默认值是 45 -XX:ClassUnloadingWithConcurrentMark并发标记类卸载默认启用所有对象都经过并发标记后就可以知道哪些类不再被使用当一个类加载器的所有类都不再使用则卸载它所加载的所有类 -XX:G1NewSizePercent新生代占用整个堆内存的最小百分比默认5 -XX:G1MaxNewSizePercent新生代占用整个堆内存的最大百分比默认60 -XX:G1ReservePercent10保留内存区域防止 to spaceSurvivor中的 to 区溢出 调优
G1 的设计原则就是简化 JVM 性能调优只需要简单的三步即可完成调优 开启 G1 垃圾收集器 设置堆的最大内存 设置最大的停顿时间STW
不断调优暂停时间指标 XX:MaxGCPauseMillisx 可以设置启动应用程序暂停的时间G1会根据这个参数选择 CSet 来满足响应时间的设置 设置到 100ms 或者 200ms 都可以不同情况下会不一样但设置成50ms就不太合理 暂停时间设置的太短就会导致出现 G1 跟不上垃圾产生的速度最终退化成 Full GC 对这个参数的调优是一个持续的过程逐步调整到最佳状态
不要设置新生代和老年代的大小 避免使用 -Xmn 或 -XX:NewRatio 等相关选项显式设置年轻代大小G1 收集器在运行的时候会调整新生代和老年代的大小从而达到我们为收集器设置的暂停时间目标 设置了新生代大小相当于放弃了 G1 的自动调优我们只需要设置整个堆内存的大小剩下的交给 G1 自己去分配各个代的大小