说说 Java 常见的垃圾收集器

一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / Java 学习路线 / 一对一提问 / 学习打卡/ 赠书活动

目前,正在 星球 内带小伙伴们做第一个项目:全栈前后端分离博客项目,采用技术栈 Spring Boot + Mybatis Plus + Vue 3.x + Vite 4手把手,前端 + 后端全栈开发,从 0 到 1 讲解每个功能点开发步骤,1v1 答疑,陪伴式直到项目上线,目前已更新了 204 小节,累计 32w+ 字,讲解图:1416 张,还在持续爆肝中,后续还会上新更多项目,目标是将 Java 领域典型的项目都整上,如秒杀系统、在线商城、IM 即时通讯、权限管理等等,已有 870+ 小伙伴加入,欢迎点击围观

话说 Java 开发的一大特色就是垃圾回收机制,它极大的提高了开发人员的开发效率。而如今垃圾回收机制几乎成为现代语言的标配了。那么在 Java 平台中常见的垃圾回收器有哪些呢?

其实,垃圾收集器是和具体的 JVM 息息相关的,不同的厂商(IBM, Oracle), 不同版本的 JVM, 提供的选择也是不同的。接下来,就谈谈主流 oracle JDK:

  • 1.Serial GC

它是最古老的垃圾回收器,Serial 体现在它的收集工作是单线程的,并且在垃圾回收过程中,会引入臭名昭著的 “Stop the world” 状态。当然,它也并不是没有一点可取之处,其单线程设计也意味着精简的 GC 实现,无需维护复杂的数据结构,初始化也很简单,所以一直是 Client 模式下 JVM 默认选项。

Serial GC 对应的 JVM 参数如下:

-XX:+UseSerialGC
  • 2.ParNew GC

它是一个新生代的 GC 实现,它实际上是 Serial GC 的多线程版本,最常见的应用场景是配合老年代的 CMS GC 工作,下面是对应参数:

-XX:+UseConcMarkSweepGC -XX:+UseParNewGC
  • 3.CMS (Concurrent Mark Sweep) GC

它基于标记 - 清除 (Mark-Sweep)算法,设计目标是为了尽量减少停顿时间,通常对于响应时间较为敏感的应用非常重要,到今天位置,还是有很多系统在使用 CMS GC.

但是,CMS GC 采用的标记 - 清除算法存在内存碎片化的问题,所以难以避免在长时间下发生 full GC, 导致恶劣的停顿。另外,Cocurrent 强调并发,就意味着占用更多的 CPU 资源,并和用户线程争抢。

  • 4.Parrallel GC

在早期 JDK 8 版本中,它是 Server 模式 JVM 默认的 GC 选择,也被称为是吞吐量优先的 GC. 它的算法和 Serial GC 比较相似,尽管要复杂的多,其特点是新生代和老年代 GC 是并行进行的,所以在常见的服务器环境中要更加高效。开启选项如下:

-XX:+UseParrallelGC

还有就是,Parrallel GC 引入了友好的开发选项,我们可以直接设置暂停时间或吞吐量等目标,JVM 会自动进行适应性调整,例如:

-XX:MaxGCPauseMillis=value
-XX:GCTimeRatio=N // GC 时间和用户时间比例 = 1 / (N+1)
  • 5.G1 GC

G1 GC 是一种兼顾吞吐量和停顿时间的 GC 实现,也是 JDK 9 以后默认的 GC 选项。在 G1 GC 仍然存在这年代的概念,但是其内存结构并不是简单的条带式划分,而是类似棋盘的一个个 region. Region 之间是复制算法,但整体上实际可看做标记 - 整理 (Mark - Compact)算法,可以有效的避免内存碎片,尤其是当 Java 堆非常大时, G1 的优势更加明显了。

G1 的吞吐量和停顿表现有很出色,并且 jdk 团队还在持续不断的优化中。需要的注意的是 CMS 已经在 JDK 9 中标记为废弃了。