前言

视频教程:https://www.bilibili.com/video/BV1Dz4y1A7FB?p=2&vd_source=85ac5ee1b07df12a44b648a8751d30f6

相关知识点

什么是垃圾

运行程序中没有任何指针指向的对象。

Java垃圾回收的重点区域

堆和方法区

垃圾回收算法

垃圾判别算法

  • 引用计数法:对每个对象保存一个整型的引用计数器属性。用于记录对象被引用的情况。

    • 优点:实现简单,便于辨识;效率高。

    • 缺点:存在循环引用的情况。

      image-20240424062846318

  • 可达性分析法(Java使用):就是将对象及其引用关系看作一个图,选定活动的对象作为 GC Roots,然后跟踪引用链条(Reference Chain),如果一个对象和GC Roots之间不可达,也就是不存在引用链条,那么即可认为是可回收对象。

    • 优点:有效的解决循环引用的问题。
    • 缺点:可达性分析时会有STW(即使是CMS,在枚举根节点时也必须要STW)

有哪些对象可以是GC Roots

  • 虚拟机栈中引用的对象
  • 本地方法栈中引用的对象
  • 类静态属性引用的对象
  • 方法区中常量引用的对象
  • 所有被同步锁synchronized持有的对象
  • JVM内部的引用(基本数据类型对应的Class对象,常驻的异常对象,系统类加载器)
  • 反映JVM内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存等

由于GC Root采用栈方式存放变量和指针,所以如果一个指针,它保存了堆内存里面的对象,但是自己又不存放在堆内存里面,那它就是一个GC Root 。

垃圾清除算法

垃圾清除算法主要有标记-清除、复制、标记-压缩、分代收集、增量收集、分区。

标记-清除

  • 标记:Collector从引用根节点开始遍历,标记所有被引用的对象。一般是在对象的Header中记录为可达对象。
  • 清除:Collector对堆内存从头到尾进行线性的遍历,如果发现某个对象在其Header中没有标记为可达对象,则将其回收。

缺点:效率低,需要遍历两次;GC时,需要STW;容易产生内存碎片

这里所谓的清除并不是真的置空,而是把需要清除的对象地址保存在空闲的地址列表里。内存不够时再清除

image-20240424064015614

复制算法

将内存空间分为两块,每次只使用其中一块,在垃圾回收时将正在使用的内存中的存活对象复制到未被使用的内存块中,之后清除正在使用的内存块中的所有对象,交换两个内存的角色,最后完成垃圾回收。

优点:

  • 没有标记和清除过程,实现简单,运行高效
  • 复制过去以后保证空间的连续性,不会出现“碎片”问题

缺点:

  • 需要两倍的内存空间
  • 对于G1这种分拆成为大量region的GC,复制而不是移动,意味着GC需要维护region之间对象引用关系,不管是内存占用或者时间开销也不小
  • 如果系统中的存活对象很多,复制算法不会很理想。因为复制算法需要复制的存活对象数量并不会太大,或者说非常低才行。

新生代常用的垃圾回收算法

image-20240424064451166

标记-压缩算法(标记-整理)

从根节点开始标记所有被引用对象,将所有的存活对象压缩到内存的一端,按顺序排放。

优点:

  • 消除了标记/清除算法当中,内存区域分散的缺点,我们需要给新对象分配内存时,JVM只需要持有一个内存的起始地址即可
  • 消除了复制算法当中,内存减半的高额代价

缺点:

  • 从效率上来说,标记-压缩算法要低于复制算法。(效率不高,不仅要标记所有存活对象,还要整理所有存活对象的引用地址;对于老年代每次都有大量对象存活的区域来说,极为负重)
  • 移动对象的同时,如果对象被其他对象引用,则还需要调整引用的地址
  • 移动过程中,需要全程暂停用户应用程序。即:STW

image-20240424064815073

分代收集算法

不同生命周期的对象可以采取不同的收集方式,以便提高回收效率。

  • 年轻代:区域相对老年代较小,对象生命周期短、存活率低,回收频繁。一般采用复制算法

  • 老年代:区域较大,对象生命周期长、存活率高,回收不及年轻代频繁。一般采用标记-清除或者标记-清除与标记-整理的混合实现

增量收集算法

垃圾收集线程只收集一小片区域的内存空间,接着切换到应用程序线程。依次反复,直到垃圾收集完成。

  • 优点:尽可能的减少STW的情况
  • 缺点:系统吞吐量下降

分区算法

分代算法将按照对象的生命周期长短划分成两个部分,而分区算法将整个堆空间划分成连续的不同小区间。

  • 优点:每一个小区间都独立使用,独立回收。这种算法的好处是可以控制一次回收多少个小区间。

相关概念

System.gc()

在默认情况下,通过System.gc()或者Runtime.getRuntime().gc()的调用,会显式触发Full GC,同时对老年代和新生代进行回收,尝试释放被丢弃对象占用的内存。

**Java中调用System.gc()方法并不一定会立即触发垃圾回收。**System.gc()方法只是向 JVM 提出一个垃圾回收的建议,具体的垃圾回收时间及方式仍然由 JVM 决定。

finalize()

垃圾回收器在回收某个对象的时候,首先会调用该对象的finalize()方法

特点:

  • Java不保证finalize方法会被及时地执行
  • finalize方法可能会带来性能问题。因为JVM通常在单独的低优先级线程中完成finalize的执行
  • finalize方法中,可将待回收对象赋值给GC Roots可达的对象引用,从而达到对象再生的目的
  • 一个对象的finalize方法至多由GC执行一次

finalize()是Object的protected方法,子类可以覆盖该方法以实现资源清理工作

finalize的执行过程(生命周期)

当对象变成(GC Roots)不可达时,GC会判断该对象是否覆盖了finalize方法,若未覆盖,则直接将其回收。否则,若对象未执行过finalize方法,将其放入F-Queue队列,由一低优先级线程执行该队列中对象的finalize方法。执行finalize方法完毕后,GC会再次判断该对象是否可达,若不可达,则进行回收,否则,对象“复活”。

内存溢出和内存泄露

内存溢出:是真实有用的对象,占用了内存空间,当需要更多内存空间时,内存空间不足,内存溢出。

内存溢出的原因

1
2
1Java虚拟机的堆内存设置不够
2)代码中创建了大量大对象,并且一直被引用导致不能被回收。

内存泄露:是无用的对象(应用中无实际作用),占用了内存空间,当GC时又不能回收它们。

内存泄漏并不会立刻引起程序崩溃

内存泄露的几种情况

长生命周期的对象持有短生命周期对象的引用,尽管短生命周期的对象不再使用,但是因为长生命周期对象持有它的引用而导致不能被回收。

1
2
3
4
5
6
7
8
1)静态集合类存放外部对象。静态集合类的生命周期与JVM程序一致,当容器中的对象在程序结束之前将不能被释放,从而造成内存泄漏。
2)单例模式持有外部对象。
3)内部类持有外部类。
4)各种连接。数据库、网络、IO连接。
5)变量作用域不合理。
6)改变对象Hash值。对象修改后的哈希值与最初存储进HashSet集合中时的哈希值就不同了,在这种情况下,即使在contains方法使用该对象的当前引用作为的参数去HashSet集合中检索对象,也将返回找不到对象的结果,这也会导致无法从HashSet集合中单独删除当前对象,造成内存泄漏。
7)缓存泄露。
8)监听与回调。

OOM之前一定会GC?

不一定。通常在抛出OOM之前会GC,但是如果分配一个超大的对象,超过了堆的最大值,JVM直接抛出OOM。

什么是STW?

Stop-the-World ,简称STW,指的是GC事件发生过程中,会产生应用程序的停顿。停顿产生时整个应用程序线程都会被暂停,没有任何响应,有点像卡死的感觉,这个停顿称为STW。

  • STW事件和采用哪款GC无关,所有的GC都有这个事件。
  • STW是JVM在后台自动发起和自动完成的。在用户不可见的情况下,把用户正常的工作线程全部停掉。
  • 开发中不要用System.gc();会导致Stop-the-world的发生。

垃圾回收的并行和并发

垃圾回收串行:单线程执行垃圾回收。

垃圾回收并行:多线程执行垃圾回收,但此时用户线程仍处于等待状态。

垃圾回收并发:用户线程与垃圾收集线程同时执行(但不一定是并行的,可能会交替执行),垃圾回收线程在执行时不会停顿用户程序的运行,用户程序在继续运行,而垃圾收集程序线程运行于另一个CPU上。

安全点和安全区域

安全点:程序执行时并非在所有地方都能停顿下来开始 GC,只有在特定的位置才能停顿下来开始GC,这些位置称为“安全点(Safepoint)”

常见的安全点:方法调用、循环跳转和异常跳转

安全区域:安全区域是指在一段代码片段中,对象的引用关系不会发生变化,在这个区域中的任何位置开始GC都是安全的。我们也可以把 Safe Region 看做是被扩展了的 Safepoint。

JAVA中的引用————垃圾回收相关

强引用:不回收。

  • 强引用可以直接访问目标对象。
  • 强引用所指向的对象在任何时候都不会被系统回收,虚拟机宁愿抛出OOM异常,也不会回收强引用所指向对象。
  • 强引用可能导致内存泄漏。

软引用:内存不足时回收。

  • 软引用通常用来实现内存敏感的缓存。比如:高速缓存就有用到软引用。

弱引用:发现即回收。

  • 弱引用非常适合来保存那些可有可无的缓存数据。
  • 弱引用对象与软引用对象的最大不同就在于,当GC在进行回收时,需要通过算法检查是否回收软引用对象,而对于弱引用对象,GC总是进行回收。弱引用对象更容易、更快被GC回收。

虚引用:对象回收跟踪。

  • 为一个对象设置虚引用关联的唯一目的在于跟踪垃圾回收过程。比如:能在这个对象被收集器回收时收到一个系统通知。
  • 随时都可能被垃圾回收器回收。
  • 由于虚引用可以跟踪对象的回收时间,因此,也可以将一些资源释放操作放置在虚引用中执行和记录。

终结期引用:它用以实现对象的finalize()方法,也可以称为终结器引用。

  • 无需手动编码,其内部配合引用队列使用。
  • 在GC时,终结器引用入队。由Finalizer线程通过终结器引用找到被引用对象并调用它的finalize()方法,第二次GC时才能回收被引用对象。

面试题

讲讲JVM的gc (携程)
GC是什么?为什么要有GC? (蚂蚁金服)
垃圾回收的优点和原理。 (蚂蚁金服)
垃圾回收机制等 (支付宝)
GC回收的是哪部分的垃圾?(vivo)
垃圾回收的优点和原理?基本原理是什么?(瓜子)
GC是什么?为什么要有GC? (美团)
简述Java垃圾回收机制 (美团)
垃圾回收的优点和原理。(美团)

1

GC算法都有哪些?他们之间的区别是什么?(菜鸟)
JVM的常用的GC算法(高得地图)
GC垃圾回收机制算法(数信互融科技发展有限公司)
GC的算法,复制算法和标记清除的优缺点?(迪原创新)
常用的GC算法,如何确定哪些是要被清除的哪些是不能被清除(网易邮箱、美团)
垃圾回收机制的几种回收算法(亚信)
GC算法都有哪些?他们之间的区别是什么?各自的适用场景?(B站)
GC 的三种收集方法:标记清除、标记整理、复制算法的原理与特点,分别用在什么地方,如果让你优化收集方法,有什么思路?(腾讯)
如和判断一个对象是否存活?(唯品会)
Java 中垃圾收集的方法有哪些?(苏宁)
你是用什么方法判断对象是否死亡?(滴滴)
如何判断一个对象是否存活? (蚂蚁金服)
垃圾收集策略和算法 (百度)
常见的垃圾回收器算法有哪些,各有什么优劣?(网易)
JVM有哪些回收算法,对应的收集器有哪些? (蚂蚁金服)
JVM GC算法有哪些,目前的JDK版本采用什么回收算法 (蚂蚁金服)
垃圾回收算法的实现原理。 (京东)
讲一下JVM中如何判断对象的生死? (京东)
如何选择合适的垃圾收集算法? (阿里)
讲一讲垃圾回收算法。 (阿里)
JVM有哪些回收算法,对应的收集器有哪些? (拼多多)
讲讲你知道的垃圾回收算法 (字节跳动)
Java对象的回收方式,回收算法。 (字节跳动)
JVM垃圾收集算法与收集器有哪些? (京东)
常见的垃圾回收器算法有哪些,各有什么优劣?(阿里-天猫、UC)
有哪些垃圾回收方法,jdk8的垃圾收集器是什么?(搜狐、万达集团)
如何判断一个对象是否存活?(或者GC对象的判定方法) (美团)
常见的垃圾回收器算法有哪些,各有什么优劣? (字节跳动)

1

Java GC机制?GC Roots有哪些? (拼多多)
JVM怎样判断一个对象是否可回收,怎样的对象才能作为GC root (腾讯)
Java GC机制?GC Roots有哪些? (字节跳动)
哪些部分可以作为GC Root? (字节跳动)
Java GC机制?GC Roots有哪些? (抖音)
Java GC机制?GC Roots有哪些? (京东)
GC root如何确定,哪些对象可以作为GC Root? (美团)

1

JVM的垃圾回收为什么采用分代GC。跟语言有关系吗?(阿里-钉钉)
分代的意义说一下 (阿里-钉钉)
GC分代算法(花旗银行)
说一下gc算法,分代回收说下 (百度)
Java怎么进行垃圾回收的?什么对象会进老年代? 垃圾回收算法有哪些?为什么新生代使用复制算法? (京东)
分代垃圾回收过程? (美团)
GC如何分代的?各代用什么算法回收? (美团)

1
垃圾清除算法

System.gc()和Runtime.getRunTime().gc()会做什么事情? (字节跳动)

1
2
3
4
5
6
7
8
9
10
```

**什么是内存泄漏和什么是内存溢出 (陌陌)
Java存在内存泄漏吗,内存泄漏的场景有哪些,如何避免(百度)
Java 中会存在内存泄漏吗,简述一下?(猎聘)
内存泄漏是怎么造成的?(拼多多、字节跳动)
内存泄漏与内存溢出的区别 (字节跳动)
Java存在内存溢出的现象吗 (字节跳动)
Java中会存在内存泄漏吗,请简单描述。 (美团) **

1
2
3

**什么是Full GCGC? major GC? stop the world (腾讯)**

1
2
3

**SafePoint 是什么(360安全)**

1
2
3
4

**强引用、软引用、弱引用、虚引用的区别?(字节跳动)
你开发中使用过WeakHashMap吗?(京东)**