小蔡学Java

六种常见的垃圾回收器

2024-04-07 17:05 1358 0 JVM / JUC 垃圾回收JVM

jdk 1.8 分代模型:

常见的垃圾回收器:

(1)串行垃圾回收器(Serial + SerialOld)

单线程的工作方式(会暂停所有用户线程)

注意演化的变化!!

(2)并行的垃圾回收器(高吞吐量)(Parallel Scavenge + Paraller Old) 并行的垃圾回收器

[jdk 8默认的垃圾回收器]

综上四种垃圾回收器 Serial SerialOld PS PO都会导致一个现象: 用户线程的阻塞 !

  • 用户线程暂停 <==> STW
  • 垃圾收集的时候, 用户在访问的时候会直接卡 住...没有线程给用户来用.

(3)并发的垃圾回收器[高响应速度] ParNew(新生代) + CMS(老年代)

ParNew是在Serial基础上做的改良,配合CMS使用,但大致没什么变化!

别的老年代的Serial Old和PO都采取"标记整理",但是CMS采取"标记清除"!!

(1) 初始标记:

找到所有 GC Root 根对象,短暂 STW .简单标记一下

(2) 并发标记:

  • 根据 GC Root 根对象进行对象图的遍历.且该阶段 不会暂停用户线程,允许gc和用户线程并发执行
  • 通过 写屏障技术 记录下发生错标问题的黑色对象..并放入队列中

(3) 重新标记:

会通过"增量更新"的解决方案解决上一阶段产生的错标问题.

(4) 并发清理:

清理掉确定会被回收的垃圾

浮动垃圾:

  • gc线程与用户线程并发进行 的阶段,gc线程在"并发标记"阶段,在搜集垃圾,
  • 但是在此时阶段用户线程的操作导致的原先通过"初始标记""非垃圾对象"变为"垃圾对象",
  • 而此时gc收集器无法检测到,则该垃圾对象被称为"浮动垃圾".

错标:

  • "初始标记"的垃圾对象,在"并发标记"阶段因为用户线程的影响变为了非垃圾对象.
  • 此时称为错标!

注意:

  • (1) 浮动垃圾无所谓,在下次垃圾回收的时候会把该垃圾回收 .不会有什么特别的影响. 但是"错标"的线程,会导致要使用的对象被回收了.就会造成影响.所以接下来的"重新标记"阶段就是解决"错标"的问题!!!
  • (2) "初始标记""重新标记" 都会产生极其短暂的STW.但可忽略不计!
  • (3)当 CMS并发处理失败的 时候,会立马切换 Serial Old 来清理!
  • (4) CMS解决 错标问题采用了"增量更新" 的方式.对于那些黑色增加对白色的引用,会通过 写屏障的技术记录下来,再重新标记阶段进行以黑色为根重新扫描一遍,来解决错标的问题!

不好的地方:

  • (1)内存碎片
  • (2)浮动垃圾
  • (3) 如果CMS运行期间预留的空间不足以让用户线程分配一个对象,则并发失败.并发失败时会先冻结用户线程,然后启动Serial Old来收集老年代.

总结:

(1)CMS解决了什么样的问题??

  • 解决了STW时间过长的问题,使垃圾回收时用户的等待时间变短

(2)jdk 1.8之前都是分代垃圾回收,所以就是这么分代垃圾回收器.

  • jdk 1.8之后都是分区垃圾回收.所以G1 ZGC等就没有老年代 新生代这种概念了!

补充:

1.吞吐量

2.是否要发生STW的一个重要依据是什么???

  • 是否要 移动对象 !

3.标记清除和标记整理最大的本质区别是什么?

  • (1) 前面的标记动作都一样, 标记整理算法需要所有存活的对象移动挨到一起 .而标记清除算法直接删除,所以也会有内存碎片.

4.为什么CMS要采用标记清除?而不是标记整理??

  • 因为标记整理算法涉及到对象的移动,在 对象移动阶段必须STW .而CMS的第四阶段并发清理阶段,是不会STW的,是要允许用户线程不能被STW的

五. CMS并发失败的问题?

在第四阶段并发清理阶段CMS不会STW,依旧 gc线程和用户线程 一起运行.并不能像别的老年代垃圾回收器那样等待垃圾快满了再回收, 而是在并发清理阶段预留一定的空间给程序运行.当无法为程序分配足够的空间时,则并发失败,冻结用户线程,然后换为Serial Old来清理.

别的垃圾回收器: 我gc线程垃圾回收之后你用户线程再使用, CMS就是在并发清理(回收阶段)也会让你用户线程继续跑.所以CMS就需要在垃圾回收阶段预留给用户线程足够的空间来使用,一旦用户线程要使用的空间大于预留的空间,则并发失败!

六.CMS最严重的两个问题?以及优化??

标记清除造成的内存碎片问题

晋升失败时候,新生代发生Minnor GC,幸存区中放不下要存活的对象,只能触发对象担保机制,晋升老年代,由于内存碎片过多,导致大对象没法被放下!

解决: 让CMS进行一定次数的Full GC的后进行一次标记整理的算法,控制住内存碎片的数量.可以通过参数配置...

并发失败时的Serial Old

解决: 降低触发CMS GC的阈值 ...让其预留够足够的空间!

评论( 0 )

  • 博主 Mr Cai
  • 坐标 河南 信阳
  • 标签 Java、SpringBoot、消息中间件、Web、Code爱好者

文章目录