0
点赞
收藏
分享

微信扫一扫

JVM基础 - GC篇

独孤凌雪 2021-09-29 阅读 125
随笔

HotSpot 垃圾回收器

全网最硬核 JVM TLAB 分析
HotSpot虚拟机垃圾收集优化指南
垃圾回收的第一步,就是找出活跃的对象。根据 GC Roots 遍历所有的可达对象,这个过程,就叫作标记。标记完成后,把其他不活跃的对象判定为垃圾,然后删除。所以垃圾回收只与活跃的对象有关,和堆的大小无关。

JVM GC可以分为:

  • Minor GC:发生在年轻代的 GC。
  • Major GC:发生在老年代的 GC。
  • Full GC:全堆垃圾回收。比如 Metaspace 区引起年轻代和老年代的回收。

年轻代垃圾回收器

  • Serial 垃圾收集器: 单线程处理 GC ,使用复制算法, 回收的过程中暂停一切用户线程
  • ParNew 垃圾收集器: 多线程处理 GC ,回收的过程中暂停一切用户线程
  • Parallel Scavenge 垃圾收集器: 另一个多线程版本的垃圾回收器, 追求 CPU 吞吐量, 适合弱交互强计算

老年代垃圾回收器

老年代的对象存活率一般是比较高的, 空间又比较大使用复制算法不划算, 所以一般使用“标记-清除”、“标记-整理”算法,采取就地收集的方式。

  • Serial Old 垃圾收集器: Serial收集器的老年代版本,单线程, 使用标记-整理算法。
  • Parallel Old 垃圾收集器: Parallel Old 收集器是 Parallel Scavenge 的老年代版本,追求 CPU 吞吐量。
  • CMS 垃圾收集器: CMS(Concurrent Mark Sweep)收集器是以获取最短 GC 停顿时间为目标的收集器,它在垃圾收集时使得用户线程和 GC 线程能够并发执行,因此在垃圾收集过程中用户也不会感到明显的卡顿。从后续更高版本的JDK版本提示来看, CMS 垃圾回收器逐步被G1 等垃圾回收器取代掉。
  • G1、ZGC 垃圾收集器: 启动参数添加-XX:+UseG1GC, -XX:+UseZGC

TLAB(Thread Local Allocation Buffer)

查看GC配置信息

通过-XX:+PrintCommandLineFlags参数,可以查看当前 Java 版本默认使用的垃圾回收器-XX:InitialHeapSize=126596288 -XX:MaxHeapSize=2025540608 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC

JDK1.8默认使用UseParallelGC, 由ParallelScavenge(年轻代) + ParallelOld(老年代)组成, 可通过自带的工具jmc查看相关信息, 启用飞行记录器在JVM启动时需要添加参数-XX:+UnlockCommercialFeatures -XX:+FlightRecorder

CMS垃圾回收器

把遍历对象图过程中遇到的对象,按“是否访问过”这个条件标记成以下三种颜色(三色标记):

  • 白色:尚未被GC访问过的对象,如果全部标记已完成依旧为白色的,称为不可达对象,既垃圾对象。
  • 黑色:本对象已经被GC访问过,且本对象的子引用对象也已经被访问过了。
  • 灰色:本对象已访问过,但是本对象的子引用对象还没有被访问过,全部访问完会变成黑色,属于中间态。
步骤:

初始标记 -> 并发标记 -> 并发预清理 -> 可中止的并发预清理 -> 重新标记 -> 并发清理 -> 并发重置

也可以简化理解为四个阶段: 初始标记->并发标记->重新标记->并发清理. 有两个阶段会发生stop-the-world(初始标记和重新标记阶段),其他阶段都是并发执行的。

G1垃圾回收器

HotSpot虚拟机垃圾收集调优指南-第九章

G1 的回收过程主要分为 3 类:

  • G1“年轻代”的垃圾回收,同样叫 Minor GC,这个过程和我们前面描述的类似,发生时机就是 Eden 区满的时候。
  • 老年代的垃圾收集,严格上来说其实不算是收集,它是一个“并发标记”的过程,顺便清理了一点点对象。
  • 真正的清理,发生在“混合模式”,它不止清理年轻代,还会将老年代的一部分区域进行清理。


简单来说, 就是原本内存连续的堆切分成了均等大小的名字叫作小堆区(Region), Region的大小1M 到 32M 字节之间的一个 2 的幂值数。小堆区可以是 Eden 区,也可以是 Survivor 区,还可以是 Old 区。所以 G1 的年轻代和老年代的概念都是逻辑上的. 垃圾最多的小堆区,会被优先收集。这就是 G1 名字的由来

步骤

初始标记->Root 区扫描(Root Region Scan)->并发标记->重新标记->清理阶段

G1的过程和 CMS 垃圾回收器的回收过程非常类似,初始标记和重新标记阶段也是STW

  • 并发标记: 这个阶段从 GC Roots 开始对 heap 中的对象标记,标记线程与应用程序线程并行执行,并且收集各个 Region 的存活对象信息。
  • 清理阶段: 如果发现 Region 里全是垃圾,在这个阶段会立马被清除掉。不全是垃圾的 Region,并不会被立马处理,它会在 Mixed GC 阶段,进行收集。
CSet

全称是 Collection Set,即收集集合,保存一次 GC 中将执行垃圾回收的区间(Region)。GC 是在 CSet 中的所有存活数据(Live Data)都会被转移。

SATB 算法

全称是 Snapshot At The Beginning,它作用是保证在并发标记阶段的正确性。



这个快照是逻辑上的,主要是有几个指针,将 Region 分成个多个区段。如图所示,并发标记期间分配的对象,都会在 next TAMS 和 top 之间。

RSet

RSet 是一个空间换时间的数据结构。RSet 的功能与卡表(Card Table)类似,它的全称是 Remembered Set,用于记录和维护 Region 之间的对象引用关系。RSet 记录了其他 Region 中的对象引用本 Region 中对象的关系,属于 points-into 结构(谁引用了我的对象),有点倒排索引的味道。

混合回收(Mixed GC)

能并发清理老年代中的整个整个的小堆区是一种最优情形。混合收集过程,不只清理年轻代,还会将一部分老年代区域也加入到 CSet 中。

ZGC垃圾回收器

所以垃圾回收器本身的优化和升级,从来都没有停止过。最新的 ZGC 垃圾回收器,
就有 3 个令人振奋的 Flag:

  • 停顿时间不会超过 10ms;
  • 停顿时间不会随着堆的增大而增大(不管多大的堆都能保持在 10ms 以下);
  • 可支持几百 M,甚至几 T 的堆大小(最大支持 4T)。

内存回收算法

  • 复制算法(Copy):复制算法是所有算法里面效率最高的,缺点是会造成一定的空间浪费。
  • 标记-清除(Mark-Sweep):效率一般,缺点是会造成内存碎片问题。
  • 标记-整理(Mark-Compact):效率比前两者要差,但没有空间浪费,也消除了内存碎片问题。
    所以,没有最优的算法,只有最合适的算法。

卡片标记(card marking)


该技术解决老年代到新生代的跨代引用问题。具体是,使用卡表(Card Table)和写屏障(Write Barrier)来进行标记并 加快 对GC Roots的扫描, 老年代是被分成众多的卡页(card page)的(一般数量是 2 的次幂)。卡表(Card Table)就是用于标记卡页状态的一个集合,每个卡表项对应一个卡页。

在进行 Minor GC 时, 只需要扫描由Dirty标记的区域(老年代引用了新生代对象的区域)即可, 大大加快了扫描的速度, 使GC停顿的时间减少

对象如何进入老年代

  • 提升(Promotion)

每当发生一次 Minor GC,存活下来的对象年龄都会加 1。直到达到一定的阈值,该对象提升到老年代。这些对象如果变的不可达,直到老年代发生 GC 的时候,才会被清理掉。这个阈值,可以通过参数 ‐XX:+MaxTenuringThreshold进行配置,最大值是 15

  • 分配担保

看一下年轻代的图,每次存活的对象,都会放入其中一个幸存区,这个区域默认的比例是 10%。但是我们无法保证每次存活的对象都小于 10%,当 Survivor 空间不够,就需要依赖其他内存(指老年代)进行分配担保。这个时候,对象也会直接在老年代上分配。

  • 大对象直接在老年代分配

超出某个大小的对象将直接在老年代分配。这个值是通过参数 -XX:PretenureSizeThreshold进行配置的。默认为 0,意思是全部首选 Eden 区进行分配。

  • 动态对象年龄判定

有的垃圾回收算法,并不要求 age 必须达到 15 才能晋升到老年代,它会使用一些动态的计算方法。比如,如果幸存区中相同年龄对象大小的和,大于幸存区的一半,大于或等于 age 的对象将会直接进入老年代。

这些动态判定一般不受外部控制,我们知道有这么回事就可以了。通过下图可以看一下一个对象的分配逻辑。


参考

通过 JFR 与日志深入探索 JVM - TLAB 原理详解
关于栈上分配和TLAB的理解
CMS垃圾收集器
CMS与三色标记算法
一文看透垃圾回收,深入剖析,浅入深出
JVM调优:CardTable简介
一篇文章彻底搞懂CMS与G1
Java之CMS GC的7个阶段

举报

相关推荐

【JVM】基础篇

JVM进阶篇2 - GC垃圾回收

jvm、jmm、gc

JVM - GC整理

【jvm】Major GC

JVM/GC复习

JVM基础篇---02

JVM-GC复习

0 条评论