当前位置: 首页 > news >正文

JVM虚拟机(三)垃圾回收简介、垃圾回收算法、分代回收、垃圾回收器种类、G1垃圾回收器

目录

    • 一、什么是垃圾回收?
      • 1.1 什么是垃圾回收?
      • 1.2 什么对象能被垃圾回收?
        • 1)引用计数法
        • 2)可达性分析算法
    • 二、JVM 垃圾回收算法
      • 2.1 标记清除算法
      • 2.2 标记整理算法(标记压缩算法)
      • 2.3 复制算法
      • 2.4 总结
    • 三、JVM 的分代回收
      • 3.1 堆中的区域划分
      • 3.2 分代收集算法-工作机制
      • 3.3 Minor GC、Mixed GC、Full GC 的区别是什么?
      • 3.4 总结
    • 四、JVM 有哪些垃圾回收器?
      • 4.1 单线程垃圾收集器
      • 4.2 多线程垃圾收集器
      • 4.3 并发垃圾收集器
      • 4.4 G1垃圾收集器
    • 五、G1垃圾收集器
      • 5.1 G1垃圾回收器的特点
      • 5.2 垃圾回收的三个阶段
        • 1)Young Collection(新生代垃圾回收)
        • 2)Young Collection + Concurrent Mark(年轻代垃圾回收+并发标记)
        • 3)Mixed Collection(混合垃圾回收)
      • 5.2 Humongous区
    • 六、总结

在这里插入图片描述

一、什么是垃圾回收?

1.1 什么是垃圾回收?

在介绍垃圾回收之前,我们需要先明确几个点:

  1. 为什么要进行垃圾回收呢?
  2. 回收哪里的垃圾呢?

是这样的,垃圾回收主要指的是回收堆中的对象,堆的位置如下图所示:

在这里插入图片描述

堆是一个共享区域,我们创建的对象和数组都存储在当前的堆里。但是我们也不能无限地去创建对象,也不是所有的对象都需要一直存在,如果说不进行垃圾回收的话,内存迟早都会被耗尽的,所以说及时的垃圾回收就显得非常有必要了。那什么对象才能被回收呢?

1.2 什么对象能被垃圾回收?

简单一句话就是:如果一个或多个对象没有任何的引用指向它了,那么这个对象现在就可能会被垃圾回收器回收。

定位什么样的对象是垃圾有两种方式:第一个是引用计数法,第二个是可达性算法

1)引用计数法

引用计数法:一个对象被引用了一次,在当前的对象头上递增一次引用次数,如果这个对象的引用次数为0,代表这个对象可回收。

比如下面这段代码:

String demo = new String("123");

因为我们在这里 new 了一个 String,所以会在堆中开辟一块空间去存储当前的对象:

这时,我们的引用计数法就会去增加一次引用的次数,ref=1。

假如目前的 demo 指向 null:

String demo = null;

这时,demo 就不会指向原来的那块内存了,当前的 ref 就会从 1 变成 0:

ref 变成 0 就表示当前的对象 new String(“123”) 是可以被垃圾回收的。

这个方法看起来非常简单,但是引用计数法也有一定的问题,我们来看下一个例子:

假如有下面这样一段代码:

在这里插入图片描述

我们先来分析一下这个代码:

  • 左边代码中,Demo 类中有一个 Demo 的属性指向它自己,然后还有一个 String 的 name 和一个带参构造函数。
  • 右边代码中,使用了 Demo 类创建了 a 和 b 两个实例,其中 a 的 instance 成员变量指向了 b,b 的 instance 成员变量指向了 a。

这段代码在内存中的表示方式如下:

首先,在栈中有一个变量 a 和一个变量 b,分别指向堆中的两块内存。由于除了 a 和 b 指向了这两块内存,它们之间还存在互相引用,只要有对象引用,引用次数就会加1,所以此时引用次数 ref=2。

下面我们继续执行代码:

代码中把 a 和 b 都指向 null,这时我们栈中的变量 a 和变量 b 就不再引用堆中那两块内存了,这样堆中两块内存的引用次数 ref 就会都变成 1 了,如下所示:

这时大家就会发现,目前堆中的这两个对象的引用次数都是1,但是目前这两个对象是没有人使用的,但是它们依然不会被回收。如果出现了这种情况,就是出现了 循环引用,就会引发内存泄漏。因为这两个对象一直不会被回收。

以上就是引用计数法,使用起来是非常简单,但是缺点就是容易导致内存泄漏。所以说一般不会采用这种方法去定位某个对象是否是垃圾。

下面我们看第二种定位垃圾的方式,可达性分析算法。

2)可达性分析算法

现在的虚拟机采用的都是通过可达性算法来确定哪些对象是垃圾。

首先,我们来看下面这张图:

最上面有一个 GC Roots,相当于是一个树根。从根中探索查看是否有关联的对象:

  • 如果说能关联到,不管是直接关联(如A)还是间接关联(如B),找到的这些对象都是存活的对象,这些对象就不会被垃圾回收。
  • 如果扫描堆的过程中,不能沿着 GC Roots 找到的对象,比如X、Y,它们目前没有与任何的 GC Root 进行关联,这两个就证明是可以被回收的对象。

对比我们刚才说的引用计数法,可达性分析算法能够更精确地定位哪些是可回收的垃圾。所以现在的虚拟机都是采用可达性分析算法来去确定哪些是垃圾。

其实这里还有一个问题,就是哪些对象可以作为 GC Root 呢?

一共有4种对象可以作为 GC Root:

  1. 虚拟机栈(栈帧中的本地变量表)中引用的对象: 比如下面这个示例中的 demo:

  2. 方法区中类静态属性引用的对象: 比如下面这个示例中,变量a 作为静态变量,它所引用的 new Demo() 也可以作为 GC Root。

  3. 方法区中常量引用的对象: 比如下面这个示例中,变量a 作为静态常量,这种情况下,变量a 所引用的 new Demo() 也是可以作为 GC Root 的。

  4. 本地方法栈中 JNI(即一般说的 Native 方法)引用的对象: 通过 JNI 接口由本地代码(如C/C++)持有的对象引用。

  5. 系统类加载器加载的类: 由系统类加载器加载的类,这些类本身以及它们通过静态字段持有的对象通常被认为是不可回收的。

在我们平时的开发过程中,用到前三种的对象类型会多一些。以上就是可达性分析算法。


二、JVM 垃圾回收算法

上面我们已经能够区分出内存中存活的对象和死亡的对象,GC接下来的任务就是去执行垃圾回收,释放掉那些无用对象所占用的内存空间,以便有足够的空间为新对象分配可用的内存。

目前 JVM 中就有三种比较常见的垃圾回收算法:

  • 标记清除算法
  • 复制算法
  • 标记整理算法

这三种算法每一个都有各自的特点,下面一起了解一下。

2.1 标记清除算法

标记清除 是将垃圾回收分为 2 个阶段,分别是标记和清除

  1. 对这些标记为可回收的内容进行 垃圾回收

我们先来看下面这张图:

图中蓝色部分代表 “存活的对象”,灰色部分代表 “待回收的对象”,其他的都是 “空闲的空间”。

标记清除算法的第1步就是:根据可达性分析算法得出的垃圾进行 标记

可达性分析算法就是使用 GC Root 去标记哪些是存活的对象,如下所示,可以看到蓝色部分都是被 GC Root 标记存活的对象:

标记清除算法的第2步就是:对这些标记为可回收的内容进行垃圾回收

根据步骤,标记的对象都留下来,然后直接清除没有标记的内容就可以了。回收后的效果如下:

现在这个图中只留下了蓝色的部分,这些是做了标记,属于目标存活的对象,这个就是 标记清除算法

  • 优点: 标记和清除速度较快。
  • 缺点: 内存碎片化较为严重,内存不连贯。

我们知道数组也是会存储到堆中,并且数组存储必须是一个连续的内存空间。如果我们使用了标记清除算法,由于内存不连续,有可能没有办法进行存储新的对象,也没有办法去存储一个比较大的数组。所以说这个算法用的相对比较少一些,用的比较多的主要是后面两种。

我们继续来看第二种:

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

“标记整理算法”,也称标记压缩算法,与我们刚才介绍的 “标记清除算法” 差不多,我们先看下面这张图:

首先,它也会通过 GC Root 去标记哪些对象是存活的对象,然后再去清除待回收的对象。但是它同时还多了一步,我们再来看下面这张图:

从图中可以看到,标记整理算法清除之后,它会把存活的对象进行整理,就是把所有的对象像一端移动。这样就避免了内存碎片化的问题了。但是由于标记整理算法多了一步,需要移动对象在内存中的位置,所以说它的性能也会收到一定的影响。

以上就是标记整理算法,很多老年代的垃圾回收器都是使用标记整理算法。

下面我们再来看最后一种垃圾回收算法:复制算法。

2.3 复制算法

复制算法 是将整个内存分成了大小相等的区域,标记阶段与我们前面的算法是类似的,也是通过 GC Root 进行标记哪些对象是存活的对象,然后将存活的对象进行复制,复制到另外一块内存区域。

当然,复制的过程中就自动完成了碎片的整理。如下图所示,就是回收之后的效果:

左边的 4 个对象被挪到了右边的区域,接下来把左边整个区域清空就可以了。

优点:

  • 在垃圾对象多的情况下,效率较高;
  • 清理后,内存无碎片。

缺点:

  • 分配的 2 块内存空间,在同一个时刻,只能使用一半,内存使用率较低。

一般垃圾回收的时候,年轻代的垃圾回收器都会使用复制算法。

以上就是全部的三种垃圾回收算法了,下面我们进行一下总结。

2.4 总结

JVM 垃圾回收算法有哪些?

  • 标记清除算法:垃圾回收分为 2 个阶段,分别是:标记、清除效率高,有磁盘碎片,内存不连续
  • 标记整理算法:与标记清除算法一样,将存活的对象都向内存另一端 移动,然后清理边界以外的垃圾。无碎片,对象需要移动,效率低
  • 复制算法:将原有的内存空间一分为二,每次只用其中的一块。将正在使用的对象 复制 到另一个内存空间中,然后将该内存空间清空,交换两个内存的角色,完成垃圾的回收。无碎片,内存使用率低

三、JVM 的分代回收

在之前介绍 JVM 组成的时候说话,在堆中分为新生代和老年代。下面我们就要详细说明一下,在垃圾回收的时候它们到底有什么作用。

3.1 堆中的区域划分

首先,我们还是要重新介绍一下堆中的组成:

  • 在 Java8 中,堆被分成了两份:新生代和老年代(比例为1:2)

如下图所示:

在这里插入图片描述

左边的新生代占了 1/3,右边的老年占了 2/3。在新生代中又划分为了三份:

  • 一个是伊甸园区Eden,新生的对象都分配到这里。
  • 还有两个幸存者区Survivor,分为 from 和 to。
  • Eden区、from区、to区比例为 8:1:1。

以上就是目前堆中的结构划分,下面我们来介绍一下垃圾产生之后它们是如何工作的。

3.2 分代收集算法-工作机制

  • 首先,我们刚才介绍过,新生的对象都需要存储到 Eden 区,如下图所示:

在这里插入图片描述

  • 当伊甸园区内存不足的时候(如上图所示已经占满了),这个时候 JVM 就会使用之前我们讲过的 “可达性分析算法” 来去标记 Eden 区和 from 区中存活的对象,当然目前 from 区中是没有对象的。
  • 假如标记了 A 对象是存活的,接下来就会采用 “复制算法” 将 A 对象复制到 to 区中。复制完毕之后,Eden 区和 from 区都要清空掉。操作后如下所示:

在这里插入图片描述

  • 假如经过一段时间后,Eden 区内存又出现不足,如下所示:

在这里插入图片描述

  • 这时候依然会采用 “可达性分析算法” 去标记 Eden 区和 to 区中存活的对象,然后把这些对象复制到 from 区中。
  • 假如现在 1 和 A 这两个对象依然存活,这时候就直接复制到了 from 区中,然后 Eden 区和 to 区都会清空掉。操作后如下所示:

在这里插入图片描述

  • 又经过了一段时间,又有一些新的对象存到了 Eden 区中,如下所示:

在这里插入图片描述

  • 假如这时候 A 对象被挪动的次数太多,比如超过了 15 次,那么这时候 A 对象就不会再在 from 区和 to 区之间挪过来挪过去了。它会直接把 A 对象存储到 老年代 中。因为这种情况下,我们一般认为 A 对象会被一直引用着,它的存活时间会更长一些。
  • 当然还有一种情况,假如我们的幸存者区已经内存不足了,或者说当前某个对象太大了,它也会提前晋升到老年代。例如下图中,A 对象代表挪动次数超过 15 次之后进入了老年代;而 w 对象是一个新生的对象,它并没有到达一定的挪动次数,所以 w 对象是正常地在新生代中进行复制挪动,等 w 对象挪动到一定次数也会进入到老年代中。

在这里插入图片描述

以上就是新生代和老年代工作的配合方式,但是在实际面试过程中还会问一些名词,比如:MinorGC、Mixed GC、FullGC。

3.3 Minor GC、Mixed GC、Full GC 的区别是什么?

我们前面了解到新生代和老年代的比例如下所示:

在这里插入图片描述

  • Minor GC,也称 Young GC,发生在新生代的垃圾回收,暂停时间短(STW)。
  • Mixed GC,新生代 + 老年代两块 部分 区域的垃圾回收,G1 收集器特有。
  • Full GC,新生代+老年代 完整 垃圾回收,暂停时间长(STW),应尽量避免

名词解释:

  • STW(Stop-The-World):,暂停所有应用程序线程,等待垃圾回收的完成。Minor GC 暂停时间短就说明效率比较高,如果暂停时间比较长就说明效率降低。

3.4 总结

1)堆的区域划分

  1. 堆被分为了两份:新生代和老年代【1:2】。
  2. 对于新生代,内部又被分为了三个区域:Eden区,幸存者区survivor(分成 from 和 to)【8:1:1】。

2)对象分代回收策略

  1. 新创建的对象,都会先分配到 Eden 区。
  2. 当 Eden 区内存不足,标记 Eden 区与 from 区(现阶段没有)的存活对象。
  3. 将存活对象采用复制算法复制到 to 区中,复制完毕后,Eden 区和 from 内存都得到释放。
  4. 经过一段时间后,Eden 区的内存又出现不足,标记 Eden 区和 to 区存活的对象,将其复制到 from 区。
  5. 当幸存者区对象熬过几次回收(最多15次),晋升到老年代(幸存者区内存不足或大对象会提前晋升)。

四、JVM 有哪些垃圾回收器?

在 jvm 中,实现了多种垃圾收集器,包括:

  • 单线程垃圾收集器(Serial 和 Serial Old)。
  • 多线程垃圾收集器(Parallel Scavenge 和 Parallel Old),JDK8默认
  • 并发垃圾收集器(ParNew 和 CMS)。
  • 智能并发垃圾收集器(G1),JDK9默认

我们根据新生代和老年代可以进行如下分类:

  • 新生代收集器: Serial、ParNew、Parallel Scavenge。
  • 老年代收集器: Serial Old、CMS、Parallel Old。
  • 通用收集器: G1。

常用组合:Serial + Serial OldParallel Scavenge + Parallel OldParNew + CMSG1(不需要组合)

4.1 单线程垃圾收集器

单线程垃圾收集器,也称串行垃圾收集器,包含了两个收集器:SerialSerial Old,是指使用单线程进行垃圾回收,堆内存较小,适合个人电脑。

  • Serial: 作用于新生代,采用复制算法。
  • Serial Old: 作用于老年代,采用标记-整理算法。

垃圾回收时,只有一个线程在工作,并且 Java 应用中的所有线程都要暂停(STW),等待垃圾回收的完成。

举个例子,如下图所示:

在这里插入图片描述

当前一个电脑里面有4核 CPU,绿色的线表示我们的程序在正常的运行,当到达安全点后就会产生一个垃圾回收。这时候Serial 垃圾回收器会暂停其它线程,保留一个专门的线程来进行垃圾回收。等垃圾回收线程执行完了垃圾回收之后,才能恢复运行程序的线程继续运行。

4.2 多线程垃圾收集器

多线程垃圾收集器,也称并行垃圾收集器,也包含了两个收集器:Parallel NewParallel OldJDK8默认使用此垃圾回收器

  • Parallel New: 作用于新生代,采用复制算法。
  • Parallel Old: 作用于老年代,采用标记-整理算法。

垃圾回收时,多个线程在工作,并且 Java 应用中的所有线程都要暂停(STW),等待垃圾回收的完成。

举个例子,如下图所示:

在这里插入图片描述

当前一个电脑里面有4核 CPU,对应的多个线程都在同时进行垃圾回收,对比我们刚才说的串行垃圾回收器,有更多的线程参与了垃圾回收。这个性能的确会更高一些,但是在进行垃圾回收的时候,依然也会进行线程的中断(STW)。JDK8 默认使用这种垃圾回收器

4.3 并发垃圾收集器

并发垃圾收集器,也包含了两个垃圾收集器:ParNewCMS。CMS 全程 Concurrent Mark Sweep,是一款并发的、使用标记-清除算法的垃圾回收器。该回收器是针对老年代垃圾回收的,是一款以获取最短回收停顿时间为目标的收集器,停顿时间短,用户体验就好。其最大特点是在进行垃圾回收时,应用仍然能正常运行。

举个例子,如下图所示:

在这里插入图片描述

当前一个电脑里面有4核 CPU:

  • 在进行垃圾回收的时候,首先它会有一个初始标记,这个标记就是使用我们之前讲过的 “可达性分析算法” 来标记存活的对象的,这时候会进行 STW,即标记的时候其他线程会进行阻塞状态。

  • 然后再进行并发标记,重新标记。为了方便理解,我们看下面这张图:

  • 情况一:当我们的代码在执行过程中,有可能在并发标记完成之后,本来 X 被认为是一个垃圾对象,但是在并发标记阶段的同时,我们的代码是可以正常运行的,也有可能会出现新的引用,比如:A对象又去引用了 X对象。那这个时候 X对象就不能被回收了,所以说我们在这里有一个重新标记的阶段。

  • 情况二:比如说,在一开始标记的时候,当前的 D对象的确是一个存活的对象,JVM 在重新标记的过程中,B对象取消了对 D对象的引用,那么此时的 D对象就要把它作为一个垃圾对象进行回收。

以上两种情况就体现了重新标记的重要作用,我们再回到并发垃圾收集器的回收过程:

  • 重新标记完成之后,才真正进入到并发清理的阶段。从图中可以看到,并发清理的过程中,其他线程还是可以正常运行的。

关于并发垃圾收集器,主要关注点在于停顿时间短,记住这点即可。

4.4 G1垃圾收集器

由于 G1 垃圾收集器比较重要,也是面试官常问的内容,我们单独作为一个章节进行讲解。


五、G1垃圾收集器

G1垃圾收集器 是一种智能并发垃圾收集,应用于新生代和老年代,在 JDK9 之后默认使用 G1

5.1 G1垃圾回收器的特点

  • 在 G1 垃圾收集器中划分了多个区域,每个区域都可以充当 Eden区、Survivor区、Old(老年代)、Humongous,其中 humongous 专为大对象准备。这里面并没有之前的老年代和新生代的比例划分,也没有新生代中的比例划分,每个区域都一样,并且每个区域可以存储各种对象,还专门增加了一个 humongous 区用来存储大对象。
  • 采用复制算法,没有内存碎片。
  • 响应时间与吞吐量兼顾,即效率高的同时处理任务比较多。
  • G1垃圾收集器在垃圾回收的过程中主要分为三个阶段:新生代回收、并发标记、混合收集。如下图所示:
  • 如果并发失败(或者说垃圾回收失败,即回收速度赶不上创建新对象速度),会触发 FullGC。

以上就是 G1 垃圾回收器的特点了,下面我们就从 G1垃圾回收器的工作流程入手,进行了解。

5.2 垃圾回收的三个阶段

1)Young Collection(新生代垃圾回收)

首先,我们来看一张图:

这张图表示了整个堆空间,我们把整个堆划分成了大小相等的区域。其中的每个区域都可以作为我们刚才提到的 Eden区、Survivor区、Old(老年代)、Humongous。

  • 初始时,所有区域都处于空闲状态。
  • 当创建对象时,就会挑出一些空闲区域作为 Eden区来存储这些对象。比如下图中就表明了几个 E,这些就是我们的 Eden区:
  • 随着对象越来越多,堆中的 Eden区可能快要放满了,这时就会触发一个新生代的垃圾回收。

大家可能有疑问:还有这么多的空间不去存储就开始垃圾回收了嘛?是这样的,G1垃圾收集器中新生代的占比不是固定的,它是在 5% ~ 6% 之间波动,G1会自动进行调整。但是大家可以思考一下,既然新生代的大小是被限制的,不管怎么波动都会有限制,都会限制当前的 Eden 区的大小,我们就不能随便地去创建新对象。所以说当我们的 Eden 区的数量达到一定程度后,它就会触发一次 Eden 区的垃圾回收。它也是采用复制算法,即会使用 “可达性分析算法” 去标明哪些对象是存活下来的。把所有存活的对象进行标记之后,没有标记的对象就成为垃圾了。G1就会将这些存活的对象用复制算法复制到 Survivor区中。

如下图所示:

  • 图中的 s 其实就是 Survivor 区,经过标记之后,将剩下的存活对象都复制到幸存者区,然后之前的 Eden 区就可以释放掉了,如下图所示:

大家注意,在标记的过程当中或者是刚刚复制的过程中,都需要暂停,即触发一个 STW。不过因为我们幸存者的对象相对来说是比较少的,所以暂停时间也不会太长。

以上就是新生代的第一次垃圾回收。随着时间的流逝,还会产生很多的对象,如下图所示:

后续产生的对象都会分配到 Eden区,所以 Eden区的内存就逐渐耗尽了。这时垃圾回收器就会把 Eden区中的幸存者对象和 Survivor区中的幸存者对象合并到一起,复制到一个新的幸存者区中。如下图所示:

图中出现了一个新的幸存者区,然后新的幸存者区和之前的幸存者区就会进行一次复制。

当然,这里还有一种情况,如果当前的幸存者区中有一些对象已经超过了阈值,这些比较老的对象就会晋升到老年代中。也就是说,如果一个对象经过了很多次的垃圾回收,它就会晋升到老年代,另外一部分幸存者区和伊甸园区中的幸存者对象就会复制到一个新的幸存者区中。这样一来,伊甸园区和上一次的幸存者区就可以释放了。

以上就是垃圾回收的第一个阶段:年轻代的垃圾回收。下面我们进入第二个阶段:并发的标记阶段。

2)Young Collection + Concurrent Mark(年轻代垃圾回收+并发标记)

在当前的阶段中有一个触发条件:

  • 当老年代占用内存超过阈值(默认是45%)后,触发并发标记,这时无需暂停用户线程。

其实,在老年代中找到那些存活的对象,并且给它们加上标记,这个过程是并发执行的,在此期间不会暂停用户的线程。当然这个阶段也有一次重新标记,需要处理那些漏标的对象,所以说还是需要一次 STW 的,即需要暂停用户线程。这个就是并发标记的阶段了。

并发标记完成以后,就可以进入到第三个阶段了,也就是混合收集阶段。

3)Mixed Collection(混合垃圾回收)

在混合收集阶段,它并不是一次性收集了所有的老年代的内存,那样暂停的时间会比较长,达不到预期的暂停时间。在 JVM 里面设置了一个预期的暂停时间,比如暂停时间不能超过XXms,这个是可以设置的。为了让老年代的垃圾回收不超过预期的时间,它并不是一次性把所有的老年代都进行回收,而是先挑选出回收价值比较高的对象。比如下图中标红的几个老年代:

它们里面存活的对象数量比较少,所以回收的价值比较高,即进行少量的回收就可以获得同样的内存空间。相反,其它的一些老年代对象因为存活对象比较多,回收的价值就比较低了。因此它会挑选回收价值比较高的老年代,连同我们的 Eden区和 Survivor区一起来做一次垃圾回收。这个就是混合收集(既包含了新生代的垃圾回收,也包含了老年代的垃圾回收)。

如下图所示:

在混合收集阶段中,Eden区和原有 Survivor区中存活的对象会复制到一个新的 Survivor区,而 Survivor区中到达一定挪动次数的存活对象和原有老年代中的存活对象会复制到一个新的老年代中。等混合收集完成之后,内存就得到释放了,如下图所示:

复制完成,内存得到释放,这样就完成了一次混合收集。

当然,混合收集可能要重复执行多次。因为第一次我们在预期的时间内可能会收到了刚才的三个老年代区,后续有可能再多执行几次混合收集,把剩下的老年代再重新标记,再将标记的内存逐渐地释放出来。这个就是我们第三阶段的混合收集了。

当进行了多次混合收集之后,又会进入下一轮的新生代回收、并发标记、混合收集。

以上就是 G1 垃圾回收器的三个阶段。JVM 里面还有可能出现并发失败的情况,也就是我们垃圾回收的速度小于我们创建新对象的速度,此时就会触发一次 FullGC,它的暂停时间就非常久了。但是经历了多次的 G1 垃圾回收器的三个阶段回收,它们都是并发执行的,用户的暂停时间是比较短的。一般是不会触发 FullGC 的。

5.2 Humongous区

其实还有这里一个问题:如果说一个对象太大了,一个区域放不下的话,会存入到一个 Humongous区中。如果说一块区域不够的话,会分配一块连续的区域进行存储大对象,如下图所示:

讲到这里,G1 垃圾回收器就讲完了,下面我们进行下总结。


六、总结

详细聊一下 G1 垃圾回收器:

  • 应用于新生代和老年代,在 JDK9 之后默认使用 G1
  • 划分为多个区域,每个区域都可以充当 Eden、Survivor、Old、Humongous 区,其中 Humongous 区专为大对象准备。
  • 采用复制算法。
  • 响应时间与吞吐量兼顾。
  • 分成三个阶段:新生代回收(STW)、并发标记(重新标记 STW)、混合收集。
  • 如果并发失败(即回收速度赶不上创建新对象速度),会触发 FullGC。

整理完毕,完结撒花~🌻





参考地址:

1.新版Java面试专题视频教程,java八股文面试全套真题+深度详解(含大厂高频面试真题),https://www.bilibili.com/video/BV1yT411H7YK

相关文章:

JVM虚拟机(三)垃圾回收简介、垃圾回收算法、分代回收、垃圾回收器种类、G1垃圾回收器

目录 一、什么是垃圾回收?1.1 什么是垃圾回收?1.2 什么对象能被垃圾回收?1)引用计数法2)可达性分析算法 二、JVM 垃圾回收算法2.1 标记清除算法2.2 标记整理算法(标记压缩算法)2.3 复制算法2.4 …...

JavaScript基础:js介绍、变量、数据类型以及类型转换

目录 介绍 引入方式 内部方式 外部形式 注释和结束符 单行注释 多行注释 结束符 输入和输出 输出 输入 变量 声明 赋值 关键字 变量名命名规则 常量 数据类型 数值类型 字符串类型 布尔类型 undefined 类型转换 隐式转换 显式转换 Number ✨介绍 &a…...

【牛客SQL快速入门】SQL基础(三)

一、条件函数 IF 条件函数 IF函数是最常用到的条件函数,写法为 if(xn,a,b),xn代表判断条件,如果xn时,那么结果返回a,否则返回b。 -- 把非北京大学的用户统一归为其他大学 Select device_id,if(university ‘北京大…...

Pytorch手撸Attention

Pytorch手撸Attention 注释写的很详细了,对照着公式比较下更好理解,可以参考一下知乎的文章 注意力机制 import torch import torch.nn as nn import torch.nn.functional as Fclass SelfAttention(nn.Module):def __init__(self, embed_size):super(S…...

PyCharm 2024.1 发布:全面升级,助力高效编程!

PyCharm 2024.1 发布:全面升级,助力高效编程! 文章目录 PyCharm 2024.1 发布:全面升级,助力高效编程!摘要引言 Hugging Face:模型和数据集的快速文档预览针对 JavaScript 和 TypeScript 的全行代…...

Nginx基础(06)

Nginx基础(05) uWSGI 介绍 uWSGI 是一个 Web服务器 主要用途是将Web应用程序部署到生产环境中 可以用来连接Nginx服务与Python动态网站 1. 用 uWSGI 部署 Python 网站项目 配置 Nginx 使其可以将动态访问转交给 uWSGI 安装 python 工具及依赖 安…...

【Qt 学习笔记】QWidget的windowOpacity属性 | cursor属性 | font属性

博客主页:Duck Bro 博客主页系列专栏:Qt 专栏关注博主,后期持续更新系列文章如果有错误感谢请大家批评指出,及时修改感谢大家点赞👍收藏⭐评论✍ QWidget的windowOpacity属性 | cursor属性 | font属性 文章编号&#…...

Python爬虫:requests模块的基本使用

学习目标: 了解 requests模块的介绍掌握 requests的基本使用掌握 response常见的属性掌握 requests.text和content的区别掌握 解决网页的解码问题掌握 requests模块发送带headers的请求掌握 requests模块发送带参数的get请求 1 为什么要重点学习requests模块&…...

C++traits

traits C的标准库提供了<type_traits>,它定义了一些编译时基于模板类的接口用于查询、修改类型的特征&#xff1a;输入的时类型&#xff0c;输出与该类型相关的属性 通过type_traits技术编译器可以回答一系列问题&#xff1a;它是否为数值类型&#xff1f;是否为函数对象…...

gitee和idea集成

1 集成插件 2 配置账号密码 3 直接将项目传到仓库 4直接从gitee下载项目...

阿维·威格德森(Avi Wigderson)研究成果对人工智能领域的应用有哪些影响

AI人工智能的影响 威格德森&#xff08;Avi Wigderson&#xff09;的研究成果对人工智能领域的应用产生了深远的影响。 首先&#xff0c;威格德森在计算复杂性理论、算法和优化方面的贡献为人工智能领域提供了高效、准确的计算模型和算法。他的研究帮助我们更好地理解计算问题…...

【免费领取源码】可直接复用的医院管理系统!

今天给大家分享一套基于SpringbootVue的医院管理系统源码&#xff0c;在实际项目中可以直接复用。(免费提供&#xff0c;文中自取) 系统运行图&#xff08;设计报告和接口文档&#xff09; 1、后台管理页面 2、排班管理页面 3、设计报告包含接口文档 源码免费领取方式 后台私信…...

leetcode代码记录(全排列 II

目录 1. 题目&#xff1a;2. 我的代码&#xff1a;小结&#xff1a; 1. 题目&#xff1a; 给定一个可包含重复数字的序列 nums &#xff0c;按任意顺序 返回所有不重复的全排列。 示例 1&#xff1a; 输入&#xff1a;nums [1,1,2] 输出&#xff1a; [[1,1,2], [1,2,1], [2,1…...

【数据结构与算法】之双向链表及其实现!

​ 个人主页&#xff1a;秋风起&#xff0c;再归来~ 数据结构与算法 个人格言&#xff1a;悟已往之不谏&#xff0c;知来者犹可追 克心守己&#xff0c;律己则安&#xff01; 目录 1、双向链表的结构及概念 2、双向链表的实现 2.1 要实现的接口…...

记一次奇妙的某个edu渗透测试

前话&#xff1a; 对登录方法的轻视造成一系列的漏洞出现&#xff0c;对接口确实鉴权造成大量的信息泄露。从小程序到web端网址的奇妙的测试就此开始。&#xff08;文章厚码&#xff0c;请见谅&#xff09; 1. 寻找到目标站点的小程序 进入登录发现只需要姓名加学工号就能成功…...

设计模式学习笔记 - 设计模式与范式 -总结:1.回顾23中设计模式的原理、背后的思想、应用场景等

1.创建型设计模式 创建型设计模式包括&#xff1a;单例模式、工厂模式、建造者模式、原型模式。它主要解决对象的创建问题&#xff0c;封装复杂的创建过程&#xff0c;解耦对象的创建代码和使用代码。 1.单例模式 单例模式用来创建全局唯一的对象。一个类只允许创建一个对象…...

22 文件系统

了解了被打开的文件&#xff0c;肯定还有没被打开的文件&#xff0c;就是磁盘上的文件。先从磁盘开始认识 磁盘 概念 内存是掉电易失存储介质&#xff0c;磁盘是永久性存储介质 磁盘的种类有SSD&#xff0c;U盘&#xff0c;flash卡&#xff0c;光盘&#xff0c;磁带。磁盘是…...

OVITO-2.9版本

关注 M r . m a t e r i a l , \color{Violet} \rm Mr.material\ , Mr.material , 更 \color{red}{更} 更 多 \color{blue}{多} 多 精 \color{orange}{精} 精 彩 \color{green}{彩} 彩&#xff01; 主要专栏内容包括&#xff1a; †《LAMMPS小技巧》&#xff1a; ‾ \textbf…...

【Java开发指南 | 第一篇】类、对象基础概念及Java特征

读者可订阅专栏&#xff1a;Java开发指南 |【CSDN秋说】 文章目录 类、对象基础概念Java特征 Java 是一种面向对象的编程语言&#xff0c;它主要通过类和对象来组织和管理代码。 类、对象基础概念 类&#xff1a;类是一个模板&#xff0c;它描述一类对象的行为和状态。例如水…...

Neo4j 图形数据库中有哪些构建块?

Neo4j 图形数据库具有以下构建块 - 节点属性关系标签数据浏览器 节点 节点是 Graph 的基本单位。 它包含具有键值对的属性&#xff0c;如下图所示。 NEmployee 节点 在这里&#xff0c;节点 Name "Employee" &#xff0c;它包含一组属性作为键值对。 属性 属性是…...

002 springboot整合mybatis-plus

文章目录 TestMybatisGenerate.javapom.xmlapplication.yamlReceiveAddressMapper.xmlreceive_address.sqlReceiveAddress.javaReceiveAddressMapper.javaIReceiveAddressServiceReceiveAddressServiceImpl.javaReceiveAddressController.javaTestAddressService.javaSpringboo…...

代码随想录训练营第三十五期|第天16|二叉树part03|104.二叉树的最大深度 ● 111.二叉树的最小深度● 222.完全二叉树的节点个数

104. 二叉树的最大深度 - 力扣&#xff08;LeetCode&#xff09; 递归&#xff0c;可以前序遍历&#xff0c;也可以后序遍历 前序遍历是backtracking 下面是后序遍历的代码&#xff1a; /*** Definition for a binary tree node.* public class TreeNode {* int val;* …...

Mac版2024 CleanMyMac X 4.15.2 核心功能详解 cleanmymac这个软件怎么样?cleanmymac到底好不好用?

近些年伴随着苹果生态的蓬勃发展&#xff0c;越来越多的用户开始尝试接触Mac电脑。然而很多人上手Mac后会发现&#xff0c;它的使用逻辑与Windows存在很多不同&#xff0c;而且随着使用时间的增加&#xff0c;一些奇奇怪怪的文件也会占据有限的磁盘空间&#xff0c;进而影响使用…...

【华为OD机试】执行任务赚积分【C卷|100分】

题目描述 现有N个任务需要处理&#xff0c;同一时间只能处理一个任务&#xff0c;处理每个任务所需要的时间固定为1。 每个任务都有最晚处理时间限制和积分值&#xff0c;在最晚处理时间点之前处理完成任务才可获得对应的积分奖励。 可用于处理任务的时间有限&#xff0c;请问在…...

mybatis分页实现总结

1.mybatis拦截器相关知识 1.作用 mybatis的拦截器是mybatis提供的一个拓展机制&#xff0c;允许用户在使用时根据各自的需求对sql执行的各个阶段进行干预。比较常见的如对执行的sql进行监控&#xff0c;排查sql的执行时间&#xff0c;对sql进行拦截拼接需要的场景&#xff0c…...

Vue3——html-doc-js(html导出为word的js库)

一、下载 官方地址 html-doc-js - npm npm install html-doc-js 二、使用方法 // 使用页面中引入 import exportWord from html-doc-js// 配置项以及实现下载方法 const wrap document.getElementById(test)const config {document:document, //默认当前文档的document…...

第19天:信息打点-小程序应用解包反编译动态调试抓包静态分析源码架构

第十九天 本课意义 1.如何获取到目标小程序信息 2.如何从小程序中提取资产信息 一、Web&备案信息&单位名称中发现小程序 1.国内主流小程序平台 微信 百度 支付宝 抖音头条 2.小程序结构 1.主体结构 小程序包含一个描述整体程序的app和多个描述各自页面的page …...

外观模式:简化复杂系统的统一接口

在面向对象的软件开发中&#xff0c;外观模式是一种常用的结构型设计模式&#xff0c;旨在为复杂的系统提供一个简化的接口。通过创建一个统一的高级接口&#xff0c;这个模式帮助客户端通过一个简单的方式与复杂的子系统交互。本文将详细介绍外观模式的定义、实现、应用场景以…...

PHP数组去重

public function array_unique_key($arr,$key) {$tmp_arrarray();foreach($arr as $k > $v){if(in_array($v[$key],$tmp_arr)){ //判断是否重复unset($arr[$k]); //重复则删除}else{$tmp_arr[]$v[$key]; //将值存储在临时数组中}}return $arr; } public function array…...

论软件系统的架构风格,使用三段论 写一篇系统架构师论文

软件系统的架构风格是指在软件系统设计与开发过程中&#xff0c;采用的一组相互协调的设计原则、模式和实践。这些风格不仅影响着系统的技术实现&#xff0c;还关乎到系统的可维护性、可扩展性和可靠性等关键质量属性。通过三段论的结构&#xff0c;本文旨在探讨软件系统架构风…...

有专门学做衣服网站有哪些/seo优化的方法

先前知识&#xff1a; 1.Java对数组进行初始化时&#xff0c;该数组所占的内存空间&#xff0c;数组长度都是不可变的 2.创建一个字符串&#xff0c;为字符串对象分配内存空间&#xff0c;会耗费掉一定的时间和空间代价&#xff08;CPU&#xff0c;内存&#xff09;&#xff0…...

免费手机看电影app哪个软件好/宁波seo优化定制

1.Mybatis比IBatis比较大的几个改进是什么 a.有接口绑定,包括注解绑定sql和xml绑定Sql , b.动态sql由原来的节点配置变成OGNL表达式, c. 在一对一,一对多的时候引进了association,在一对多的时候引入了collection 节点,不过都是在resultMap里面…...

wordpress播客播放器源码/seo教程视频

在登陆网站时遇到session error问题&#xff0c;通过强大的度娘最终解决了问题&#xff0c;先记录下来&#xff0c;免得以后遇到类型问题又忘了。 通过百度发现是dwr的使用问题&#xff0c;解决办法是在web.xml使用如下配置&#xff1a; <servlet><servlet-name>…...

赚钱网站如何做/百度seo关键词排名s

由于公司停了系统的密码认证&#xff0c;所有传输文件只能用其他认证方式。 rsync和scp都可以用自己的认证方式传输数据&#xff0c;rsync传输速度快&#xff0c;但是需要deamon模式运行&#xff0c;配置起来比较慢&#xff0c;而scp可以比较快速的部署两台机器之间的认证&…...

wordpress导航模板/美国搜索引擎浏览器

一、前言 二、操作过程 &#xff08;1&#xff09;先后两次进行文件修改&#xff0c;然后提交到本地仓库。 &#xff08;2&#xff09;使用 git rebase -i origin/dev 来合并提交信息。 会弹出一个编辑框 p 07c5abd Introduce OpenPGP and teach basic usage s de9b1eb Fix Pos…...

中英文网站建设企业/宁波品牌网站推广优化公司

1.安装Git 2.安装完成之后&#xff0c;点击桌面右键&#xff0c;选中git bash here 3.配置user.name,user.email(第一次使用) git config --global user.name 用户名 git config --global user.email 邮箱 4.本地生成SSH密钥&#xff0c;一直enter到结束 $ ssh-keygen -t rsa…...