JVM垃圾回收

垃圾回收

垃圾回收(Garbage Collection,GC)就是对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收。

垃圾收集器要做的事情就是进行垃圾回收,可以采用标记清除算法、复制算法、标记整理算法、分代收集算法等。

JVM 提供了多种垃圾回收器,包括 CMS GC、G1 GC、ZGC 等,不同的垃圾回收器采用的垃圾收集算法也不同,因此适用于不同的场景和需求。

如何判断对象仍然存活?

判断一个对象是否存活,也就等同于判断一个对象是否可以被回收。通常有两种方式:引用计数算法(reference counting)和可达性分析算法。

什么是引用计数法?

每个对象有一个引用计数器,记录引用它的次数。当计数器为零时,对象可以被回收。

但无法解决循环引用问题。例如,两个对象互相引用,但不再被其他对象引用,它们的引用计数都不为零,因此不会被回收。

什么是可达性分析算法?

通过一组名为 “GC Roots” 的根对象,进行递归扫描。那些无法从根对象到达的对象是不可达的,可以被回收;反之,是可达的,不会被回收。这也是 Java 垃圾回收器(如 G1、CMS 等)使用的主要算法。

Java 中可作为 GC Roots 的引用有哪几种?

所谓的 GC Roots,就是一组必须活跃的引用,不是对象,它们是程序运行时的起点,是一切引用链的源头。在 Java 中,GC Roots 包括以下几种:

  • 虚拟机栈(栈帧中的局部变量表)中引用的对象
  • 本地方法栈(Native 方法)中引用的对象
  • 方法区中类静态属性引用的对象
  • 方法区中常量引用的对象
  • 所有被同步锁持有的对象
  • JNI(Java Native Interface)引用的对象

对象可以被回收,就代表一定会被回收吗?

如果对象在进行可达性分析后发现没有与 GC Roots 相连接的引用链,那它将会被第一次标记,随后进行一次筛选,筛选的条件是此对象是否有必要执行 finalize()方法。

如果对象在在 finalize()中成功拯救自己——只要重新与引用链上的任何一个对象建立关联即可,譬如把自己 (this 关键字)赋值给某个类变量或者对象的成员变量,那在第二次标记时它就”逃过一劫“;但是如果没有抓住这个机会,那么对象就真的要被回收了。

垃圾收集算法了解吗?

垃圾收集算法主要有三种,分别是标记-清除算法、标记-复制算法和标记-整理算法。

标记-清除算法

标记-清除(Mark-Sweep)算法分为两个阶段:

  • 标记:标记所有需要回收的对象
  • 清除:回收所有被标记的对象

优点是实现简单,缺点是回收过程中会产生内存碎片。

标记-复制算法

标记-复制(Mark-Copy)算法可以解决标记-清除算法的内存碎片问题,因为它将内存空间划分为两块,每次只使用其中一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后清理掉这一块。

缺点是浪费了一半的内存空间。

标记-整理算法

标记-整理(Mark-Compact)算法是标记-清除复制算法的升级版,它不再划分内存空间,而是将存活的对象向内存的一端移动,然后清理边界以外的内存。

缺点是移动对象的成本比较高。

什么时候会触发 Full GC?

Full GC 是最彻底的垃圾收集,涉及整个 Java 堆和方法区(或元空间)。它是最耗时的 GC,通常在 JVM 压力很大时发生。

  • Young GC 之前检查老年代:在要进行 Young GC 的时候,发现老年代可用的连续内存空间 < 新生代历次Young GC后升入老年代的对象总和的平均大小,说明本次 Young GC 后可能升入老年代的对象大小,可能超过了老年代当前可用内存空间,那就会触发 Full GC。
  • Young GC 之后老年代空间不足:执行 Young GC 之后有一批对象需要放入老年代,此时老年代就是没有足够的内存空间存放这些对象了,此时必须立即触发一次 Full GC
  • 老年代空间不足,老年代内存使用率过高,达到一定比例,也会触发 Full GC。
  • 空间分配担保失败( Promotion Failure),新生代的 To 区放不下从 Eden 和 From 拷贝过来对象,或者新生代对象 GC 年龄到达阈值需要晋升这两种情况,老年代如果放不下的话都会触发 Full GC。
  • 方法区内存空间不足:如果方法区由永久代实现,永久代空间不足 Full GC。
  • System.gc()等命令触发:System.gc()、jmap -dump 等命令会触发 full gc。

知道哪些垃圾收集器?

JVM 的垃圾收集器主要分为两大类:分代收集器分区收集器,分代收集器的代表是 CMS,分区收集器的代表是 G1 和 ZGC。

在这里插入图片描述

CMS

在垃圾收集过程中,JVM 会暂停所有的用户线程,这种暂停被称为"Stop The World"事件。

CMS(Concurrent Mark Sweep)垃圾收集器是第一个关注 GC 停顿时间(STW 的时间)的垃圾收集器

CMS 垃圾收集器通过三色标记算法,实现了垃圾回收线程与用户线程的并发执行,从而极大地降低了系统响应时间,提高了强交互应用程序的体验。

CMS(Concurrent Mark Sweep)分 4 大步进行垃圾收集:

  • 初始标记(Initial Mark):标记所有从 GC Roots 直接可达的对象,这个阶段需要 Stop the World,但速度很快。
  • 并发标记(Concurrent Mark):从初始标记的对象出发,遍历所有对象,标记所有可达的对象。这个阶段是并发进行的,STW。
  • 重新标记(Remark):完成剩余的标记工作,包括处理并发阶段遗留下来的少量变动,这个阶段通常需要短暂的 STW 停顿。
  • 并发清除(Concurrent Sweep):清除未被标记的对象,回收它们占用的内存空间。
G1

G1 把 Java 堆划分为多个大小相等的独立区域(Region),每个区域都可以扮演新生代(Eden 和 Survivor)或老年代的角色。同时,G1 还有专门为大对象设计的 Region,叫 Humongous 区。大对象的判定规则是,如果一个大对象超过了一个 Region 大小的 50%,比如每个 Region 是 2M,只要一个对象超过了 1M,就会被放入 Humongous 中。

这种区域化管理使得 G1 可以更灵活地进行垃圾收集,只回收部分区域而不是整个新生代或老年代。

G1 收集器的运行过程大致可划分为这几个步骤:

①、并发标记,G1 通过并发标记的方式找出堆中的垃圾对象。并发标记阶段与应用线程同时执行,不会导致应用线程暂停。

②、混合收集,在并发标记完成后,G1 会计算出哪些区域的回收价值最高(也就是包含最多垃圾的区域),然后优先回收这些区域。这种回收方式包括了部分新生代区域和老年代区域。

选择回收成本低而收益高的区域进行回收,可以提高回收效率和减少停顿时间。

③、可预测的停顿,G1 在垃圾回收期间仍然需要「Stop the World」。不过,G1 在停顿时间上添加了预测机制,用户可以 JVM 启动时指定期望停顿时间,G1 会尽可能地在这个时间内完成垃圾回收。

有了 CMS,为什么还要引入 G1?
特性CMSG1
设计目标低停顿时间可预测的停顿时间
并发性
内存碎片是,容易产生碎片否,通过区域划分和压缩减少碎片
收集代数年轻代和老年代整个堆,但区分年轻代和老年代
并发阶段并发标记、并发清理并发标记、并发清理、并发回收
停顿时间预测较难预测可配置停顿时间目标
容易出现的问题内存碎片、Concurrent Mode Failure较少出现长时间停顿

CMS 适用于对延迟敏感的应用场景,主要目标是减少停顿时间,但容易产生内存碎片。G1 则提供了更好的停顿时间预测和内存压缩能力,适用于大内存和多核处理器环境。

垃圾回收器的作用是什么?

垃圾回收器的核心作用是自动管理 Java 应用程序的运行时内存。它负责识别哪些内存是不再被应用程序使用的(即“垃圾”),并释放这些内存以便重新使用。

这一过程减少了程序员手动管理内存的负担,降低了内存泄漏和溢出错误的风险。

工作中项目使用的什么垃圾回收算法?

我们生产环境中采用了设计比较优秀的 G1 垃圾收集器,G1 采用的是分区式标记-整理算法,将堆划分为多个区域,按需回收,适用于大内存和多核环境,能够同时考虑吞吐量和暂停时间。

或者:

我们系统采用的是 CMS 收集器,CMS 采用的是标记-清除算法,能够并发标记和清除垃圾,减少暂停时间,适用于对延迟敏感的应用。

如何判断一个类是无用的类?

方法区主要回收的是无用的类,那么如何判断一个类是无用的类的呢?

判定一个常量是否是“废弃常量”比较简单,而要判定一个类是否是“无用的类”的条件则相对苛刻许多。类需要同时满足下面 3 个条件才能算是 “无用的类”

  • 该类所有的实例都已经被回收,也就是 Java 堆中不存在该类的任何实例。
  • 加载该类的 ClassLoader 已经被回收。
  • 该类对应的 java.lang.Class 对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。

虚拟机可以对满足上述 3 个条件的无用类进行回收,这里说的仅仅是“可以”,而并不是和对象一样不使用了就会必然被回收。

  • 23
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值