查看原文
其他

JVM 如何进行垃圾回收?

面试鸭 面试鸭 2024-03-29

JVM 这一块面试现在已经成为中大厂的面试必考点,就算你面试简历上没有写 JVM,但面试官还是有可能会问你关于 JVM 垃圾回收这一块的知识,本文将对 JVM 垃圾回收这方面的知识展开精简的分析,采用图文结合的方式,加强读者的记忆。

题目

JVM 如何进行垃圾回收?

推荐解析

1)JVM 主要在哪里进行垃圾回收?

JVM 主要对 内存中的对象的垃圾回收,又称为 GC 堆(Garbage Collected Heap)。

JDK 1.7 版本堆内存分配情况:

1.新生代

2.老年代

3.永久代

JDK 1.8 版本,永久代被元空间取代,而元空间使用的是直接内存,因此堆中只剩新生代和老年代。

图源:JavaGuide

2)内存分配原则

2.1)大多数情况下,对象首先在新生代的 Eden (伊甸园) 进行分配,当 Eden 区没有足够空间进行分配时,虚拟机将发起一次 Minor GC(新生代垃圾回收)。

2.2)大对象比如(字符串、数组)需要大量连续内存空间的对象直接进入老年代。

2.3)长期存活的对象将进入老年代,这块设计对象年龄的知识,一般情况下,当对象年龄达到 15,每次逃脱 Minor GC,就会增长一岁。特殊情况下,年龄并不会到达 15就会产生晋升,直接进入老年代,有兴趣的可以去详细了解 Hot Spot 虚拟机。而且不同的垃圾回收器的默认晋升年龄是不一样的,CMS 收集器默认晋升年龄是 6。

3)如何判断对象是否死亡?

引用计数法:有对象引用计数器 +1,引用失效,计数器 -1,但无法解决循环引用之间的问题。

举个例子:A 引用 B,B 引用 A,此时需要采用后文的可达性分析算法。

可达性分析法:将 GC Roots 的对象作为起点,从这些节点开始向下搜索,节点所走过的路径称为引用链,当一个对象到 GC Roots 没有任何引用链相连的话,证明此对象是不可用的。

首先需要了解哪些可以作为 GC  Roots 根对象。

3.1)虚拟机栈(栈帧中的局部变量表)中引用的对象

3.2)本地方法栈(Native 方法)中引用的对象

3.3)方法区类静态属性引用的对象

3.4)方法区常量引用的对象

3.5)被同步锁持有的对象

3.6)JNT 引用的对象

3.7)类加载器

3.8)活跃线程(已启动且未停止的 Java 线程)

注意事项:对象被判断不可达之后并不会马上进行垃圾回收,被被标记第一次,然后进入一次筛选,当对象没有覆盖 finalized 方法或者 finalized 方法已经被虚拟机使用过了,那么就不会进行真正回收的队列,队列中还要经过第二次标记,两次都标记后,不可达,才可以被真正回收。

4)常见垃圾回收算法

4.1)标记清除算法

缺点:产生内存碎片,因此堆不规整,堆不规整,那么对象分配就会采用空闲列表的分配策略。

4.2)标记整理算法

不会产生内存碎片,但是多了整理的步骤。

4.3)复制算法

将内存分为大小相同的两块,每次使用其中的一块,当这块内存使用完毕后,将存活的对象复制到空闲的另一块。

缺点:空间浪费,每次只能使用一半,不适合老年代。

4.4)分代收集算法

新生代有大量对象会死亡,只留下少量对象而且不是大对象,因此可以采用复制算法。而老年代对象存活几率较高,可以采用标记清除或者标记整理算法。

5)常见的垃圾回收器

5.1)Serial 收集器

新生代标记复制,老年代标记整理,只使用一条垃圾收集线程去完成垃圾收集工作。因此 STW (Stop The World) 的时间会较长,造成用户体验较差。

5.2)ParNew 收集器

Serial 收集器的多线程版本,其他完全一样。

5.3)Paraller Scavenge 收集器

和 ParNew 几乎一样,但这款收集器注重吞吐量,在大数据量的时候,想要高效利用 CPU ,可以选择这款收集器,而且此款收集器有自适应调节策略。

5.4)Serial Old 收集器

Serial 收集器的老年代版本。

用途:JDK 1.5 以前和 Paraller Scavenge 搭配使用或者作为 CMS 收集器的后备方案。

5.5)Parallel Old 收集器

Parallel Scavenge 收集器的老年代版本。

5.6)CMS 收集器(重点)

目标:获取最短停顿时间,STW 时间最短,注重用户体验,主要回收老年代,采用标记-清除算法,HotSpot 虚拟机中第一款并发收集器。

5.7)G1 收集器 (重点)

目标:注重最短停顿时间和吞吐量,实现可预测停顿时间,从整体上来看标记-整理算法,从局部上来看标记-复制算法,可以用于新生代,也可以用于老年代。JDK 9 及以后默认采用 G1 收集器。

6)建议了解

建议了解三色标记法、增量更新、原始快照这些知识,是 CMS 收集器 和 G1 收集器的重点,如何处理,错标,漏标,处理浮动垃圾等等知识。

其他补充

鱼聪明 AI 的回答:

鱼聪明 AI 地址:https://www.yucongming.com/

Java 虚拟机 (JVM) 通过垃圾回收来自动管理内存,释放不再使用的对象,以避免内存泄漏和提高程序的性能。JVM 使用垃圾收集器(Garbage Collector)来执行垃圾回收的任务。下面是垃圾回收的一般过程:

  1. 标记阶段(Mark):
  • 垃圾收集器首先标记所有的活动对象,即那些仍然被引用的对象。
  • 通过根对象(如线程栈上的引用、静态变量等)开始,垃圾收集器遍历对象图,标记所有可达的对象。
  • 清除阶段(Sweep):
    • 在清除阶段,垃圾收集器删除所有未标记的对象,释放它们占用的内存。
    • 已经被标记为活动对象的对象保留在内存中。
  • 整理阶段(Compact):
    • 在某些垃圾收集算法中,可能会执行整理阶段。在整理阶段,垃圾收集器会移动活动对象,使它们在内存中连续排列,以便更好地利用内存空间。
  • 垃圾收集器选择:
    • JVM 中有不同的垃圾收集器,例如串行收集器、并行收集器、CMS(Concurrent Mark-Sweep)收集器、G1(Garbage-First)收集器等。垃圾收集器的选择取决于应用程序的性能需求和硬件配置。
  • 垃圾回收的触发:
    • 垃圾回收并不是周期性发生的,而是在 JVM 判断出内存不足时触发。当 JVM 的堆内存占用达到一定的阈值时,或者在某些情况下,例如在新生代的 Eden 区对象存活的太多时,都可能触发垃圾回收。
  • 垃圾回收算法:
    • 不同的垃圾回收器使用不同的垃圾回收算法,例如新生代常用的算法有复制算法,老年代常用的算法有标记-清除和标记-整理算法。这些算法的选择取决于内存的使用情况和性能需求。

    总体来说,垃圾回收是 Java 内存管理的一个关键方面,它通过自动管理内存来减少程序员的工作负担,但在设计和调优应用程序时,理解垃圾回收的原理和机制是很重要的。

    推荐书籍和文章

    书籍推荐:《深入理解 JVM 虚拟机》

    文章推荐:[深入理解 JVM 垃圾回收机制及其实现原理_垃圾回收机制的原理是什么]:http://t.csdnimg.cn/XxDbW

    欢迎交流

    在阅读本文后,你应该了解内存分配原则,对象如何判断是否死亡,垃圾回收算法和垃圾回收器等知识,如果想要深入了解,建议去看书籍,注重 CMS 和 G1 收集器这两个部分,关于后续的 ZGC 收集器也可以适当了解,接下来我将提出三个问题,欢迎小伙伴在评论区交流见解。

    1)对象不可达后会被马上回收吗?

    2)哪个垃圾回收器可以做到可预测的停顿时间?

    3)如何解决 CMS 收集器的错标、漏标问题?


    往期推荐

    HTTPS 的加密过程了解吗?

    什么样的字段适合加索引?索引失效了解吗?

    TCP 的三次握手和四次挥手

    TCP 和 UDP 的区别是什么?

    什么样的字段适合加索引?索引失效了解吗?

    什么是 MySQL 回表?

    继续滑动看下一个
    向上滑动看下一个

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存