Java垃圾回收器的进化史

446 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

前言

  • 众所周知,Java区别于C、C++语言的其中一个小点,就是Java的内存释放(也就是无用对象的清理)是JVM替我们程序员做的。
  • 又因为这部分代码是C、C++语言写好的,对我们Java程序员来说就多了几分神秘色彩。
  • Java语言一直在进化,除了语法功能之外,就是这个JVM的进化,而JVM的进化就不的不提起这个垃圾收集器的不断增进。

垃圾收集器是什么

顾名思义,垃圾收集器就是Java程序运行起来后,一些对象经过类加载分配内存经调用栈使用后,这个对象没用啦,这个对象就成了垃圾,对象成为垃圾不要紧,为对象分配的那些内存空间,可是宝贵的资源,所以要清理掉这些垃圾对象从而释放内存,进而为新生的对象所使用。(Java是多么环保)

垃圾回收器怎么工作

不妨你来设计一下垃圾回收器,你会做怎样的考虑:

  1. 什么样的对象被判定为垃圾对象?
  2. 这些垃圾对象和非垃圾对象如何区分?
  3. Java程序一直在运行怎么保证清理垃圾的时候又产生出新的垃圾?
  4. 用什么算法实现以上步骤,最为省时省空间? ......

JVM垃圾回收器怎么做的

针对上面提出的问题,JVM垃圾回收器都有自己的实现:

  1. Java中对象间是引用关系,那么没有被引用的对象,就是垃圾对象。
  2. Java有颜色标记、指针着色等标记这些垃圾对象/非垃圾对象,做以区分。
  3. Java运用了暂停全部线程、并发标记、读写屏障等的手段,来标记清除对象,且周而复始。
  4. Java垃圾收集器有可达性分析算法、标记整理算法、标记复制算法、标记清除等等。

JVM垃圾收集器的进化史

第一代产品:Serial收集器(JDK1.5前)

  1. 此时JVM内存模型有分代的概念(年轻代、老年代)
  2. Serial负责年轻代、Serial Old负责老年代的垃圾收集清理。
  3. Serial使用标记复制、Serial Old使用标记整理。
  4. 单线程简单高效,清理垃圾时暂停所有线程(STW)只保留GC线程。

第二代产品:Parallel Scavenge收集器

  1. 此时JVM内存模型有分代的概念(年轻代、老年代)
  2. Parallel Scavenge负责年轻代、Parallel Scavenge Old负责老年代的垃圾收集清理。
  3. Parallel Scavenge使用标记复制、Parallel Scavenge Old使用标记整理。
  4. 多线程,CPU利用率高,清理垃圾时暂停所有线程只保留GC线程。

第三代产品:Concurrent Mark Sweep(CMS)

  1. 此时JVM内存模型有分代的概念(年轻代、老年代)
  2. ParNew / Serial负责年轻代、CMS负责老年代的垃圾收集清理。
  3. CMS使用标记清理:有了三色标记算法,并发标记,并发清理等。
  4. 多线程,CPU利用率高,产生多处内存碎片。

第四代产品:Garbage-First (G1)

  1. 弱化年轻、老年分代概念,区分eden region、old region、servivor region、humongous
  2. 根据用户期望时间计算region回收价值和成本并排序
  3. 局部标记复制算法,整体标记整理。
  4. 针对大内存,指定STW时间。

第五代产品:ZGC

  1. 没有分代概念,用region概念
  2. 从以往对象头中标记对象,改为指针中保存垃圾标记信息
  3. 使用颜色指针+读屏障+映射转发形式,标记复制,标记整理都使用
  4. STW不超过1ms

截止到2022,产品迭代如此