垃圾回收

7. 垃圾回收

7.1 垃圾回收概述

垃圾:在运行程序中没有任何指针指向的对象,这个对象就是需要被回收的垃圾。

两个概念:内存溢出和内存泄漏

  • 内存溢出out of memory指程序申请内存时,没有足够的内存供申请者使用。
  • 内存泄漏memory leak程序在申请内存后,无法释放已申请的内存空间。一次内存泄漏似乎不会有大的影响,但内存泄漏堆积后的后果就是内存溢出。

C#、Java、Pyhon和Ruby等语言都是使用自动垃圾回收的思想。

7.2 垃圾回收算法

判断对象是否存活的两种方式:引用计数法可达性分析算法

只有当对象死亡,才能进行垃圾回收。

7.2.1 标记阶段:引用计数算法

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

  • 任何对象引用了A,A的引用计数器+1;当引用失败,引用计数器-1,当对象引用计数器为0,则表示对象A不可能被使用,可进行回收。

  • 优点:实现简单,垃圾对象便于辨别,判定效率高,回收没有延迟性。

  • 缺点:

    • 需要单独的字段存储计数器,增加存储空间的开销
    • 每次赋值需要更新计数器,伴随加法和减法操作,这增加了时间开销
    • 引用计数器无法处理循环引用情况,Java的垃圾回收器中没有使用这类算法。

    循环引用:

    image-20210315153104613

7.2.2 标记阶段:可达性分析算法(Java选择标记的算法)

可达性分析的垃圾收集通常也称为追踪性垃圾收集。

GC Roots根对象集合就是一组必须活跃的引用。

基本思路:

  • 以根对象集合为起始点,按照从上至下的方式搜索被根对象集合所连接 的目的对象是否可达
  • 使用可达性算法后,内存中存活对象都会被根对象集合直接或者间接连接着,搜索所走过的路径称为引用链
  • 若目的对象没有任何引用链相连,则不可达,意味着对象已经死亡,可以标记为垃圾对象
  • 在可达性分析算法中,只有被根对象集合直接或者间接连接的对象才是存活对象。
image-20210315154413950

java技术体系中固定为GC Roots

  • 虚拟机栈中引用的对象
  • 本地方法栈内JNI引用的对象
  • 方法区中类静态属性引用的对象
  • 方法区中常量引用的对象
  • 所有被同步锁synchronized持有的对象
  • Java虚拟机内部的引用
  • 反应虚拟机内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存等。

使用可达性分析算法判断内存是否可回收,name保证分析工作在一个能保障一致性的快照中进行。这点也导致GC进行时必须“Stop The World”的一个重要原因。

一致性快照

7.2.3 对象的finalization机制

Java语言提供了 对象终止(finalization)机制来允许开发人员提供对象被销毁之前的自定义处理逻辑。

垃圾回收对象之前,会调用该对象的finalize()方法(主要在对象被回收时进行资源释放,通常是一些资源释放和清理的工作,比如关闭文件、套接字和数据库连接等)。

永远不要主动的调用某个对象的finalize()方法

  • 在finalize()时可能导致对象复活
  • 一般糟糕的finalize()会严重影响GC的性能
  • finalize()方法的执行时间没有保障的,完全由GC线程决定。
  • finalize()类似于C++的析构函数,但本质上不同
  • 由于finalize()的存在,虚拟机中的对象一般处于三种可能的状态:
    • 可触及的:从根节点开始可以到达这个对象
    • 可复活的:对象所有引用都被释放,但是对象有可能在finalize()中复活
    • 不可触及的:对象的finalize()被调用,没有复活,也不可能触及。不可触及的对象不可能被复活,因为finalize()只会被调用一次。

判断一个对象是否可回收,至少要经历两次标记过程。

  • 对象到GC Roots没有引用链,第一次标记
  • 判断是否必须执行finalize()方法
    • 若对象没有重写finalize()方法或者finalize()方法已经被虚拟机调用了,则对象判定为不可触及的
    • 对象重写了finalize()方法,还未被执行,则对象会被插入到F-Queue,由一个虚拟机自动创建、低优先级的Finalizer线程触发其finalize()方法
    • finalize()方法是对象逃脱死亡的最后机会。GC会对F-Queue队列中对象进行二次标记,若对象在finalize()方法中与引用链的任何对象建立连接,则第二次标记时,对象会被移出即将回收的集合。之后,对象再次出现没有引用链存在的情况下,finalize()不会被调用,对象直接为不可触及状态。(对象的finalize()方法只会被调用一次)

7.2.5 清除阶段:标记-清除算法(Mark-Sweep)

标记-清除算法:当堆中有效内存空间被耗尽时,会停止整个程序,进行两项工作,分别是标记和清除。

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

缺点:

  • 效率不高
  • 进行GC时,要停止整个应用
  • 清理的空间内存不是连续的,产生内存碎片

注意,这里的清理不是真的置空,是把需要清理的对象地址保存在空闲的地址列表中,如果有新的对象需要加载时,判断垃圾的位置空间是否够,如果够就存放。

7.2.6 清除阶段:复制算法(Copying)

核心思想:将活着的内存空间氛围两块,每次只使用其中一块,在垃圾回收时将正在使用的内存中存活的对象赋值到未被使用的内存块中,之后清除正在使用的内存块中所有的对象,交换两个内存的角色,最后完成垃圾回收。适用于新生代。

image-20210315170429492

S0和S1区就是使用了复制算法。

优点:

  • 实现简单,运行高效
  • 赋值过去保证空间连续性,不会存在碎片问题

缺点:

  • 需要两倍的内存空间
  • 内存占用和时间开销不小
  • 当系统中的垃圾对象很多,赋值算法需要赋值的存活对象数量并不会太大,或者很低才行。

7.2.7 清除阶段:标记-压缩算法(Mark-Compact)

image-20210315172012258

标记-压缩算法是一种移动式回收算法。适用于老年代。

优点:

  • 消除了标记-清除算法的内存空间分散问题以及内存碎片化问题
  • 清除了复制算法中内存减半的高额代价

缺点:

  • 标记整理算法效率低于赋值算法
  • 移动对选哪个的时候,当对象被其他对象引用时,还需要调整引用的地址
  • 移动的过程中需要暂停用户应用程序(STW)

image-20210315172856613

7.2.8 分代收集算法(几乎所有的垃圾收集器都有分代思想)

分代收集算法:对于不同的生命周期的对象采取不同的收集方式,以便于提高回收效率。一般将java堆分为新生代和老年代,这样根据不同年代的特性使用不同的回收算法,以提高垃圾回收效率。

  • 新生代:复制算法(对象生命周期短,存活率低,回收很频繁,存活对象较少)
  • 老年代:标记-整理算法(区域较大,对象生命周期较长,存活率高,回收没有比新生代频繁)

7.2.9 增量收集算法和分区算法

增量收集算法

基本思想:如果一次性将所有的垃圾进行处理,需要造成系统长时间的停顿(STW),那么就可以让垃圾收集线程和应用线程交替执行。**每次,垃圾收集线程只收集一小片区域的内存空间,接着切换到应用程序线程。依次反复,直到垃圾收集完成。**增量收集算法的基础是标记-清除和复制算法,增量收集算法通过对线程间冲突的妥善处理,允许垃圾收集线程以分阶段的方式完成标记、清理或者复制的操作。

缺点:线程切换和上下文转换的消耗会让垃圾回收的总体成本上升,造成系统吞吐量的下降。

分区算法

分区算法主要是G1垃圾回收器来说的。

分区算法将整个堆空间划分为连续的不同小区间region,每个小区间都独立使用,独立回收。这样好处就是可以控制一次回收多少个小区间。

image-20210315201250271

7.3 垃圾回收相关概念

7.3.1 System.gc()

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

System.gc()无法保证对垃圾收集器的调用。

System.runFinalization():强制调用失去引用的对象的finalize()方法。

7.3.2 内存泄漏和内存溢出

内存溢出 OOM

OOM:没有空闲内存,并且垃圾收集器也没办法提供更多的内存。

堆内存不够的原因:

  • Java虚拟机的堆内存设置不够
  • 代码中创建了大量的大对象,并且长时间不能被垃圾收集器收集。

内存泄漏

只有对象不被程序用到而且GC又不回收他们的情况,叫做内存泄漏。(严格)

但是当很多时候一些不好的实践会导致对象的生命周期变得很长甚至导致OOM,这个也可以叫做内存泄漏(宽泛)

image-20210315204629197

7.3.3 Stop the World

STW:指在GC事件发生过程中,会产生应用程序的停顿,停顿产生时整个应用线程会被暂停,没有任何响应。

可达性分析算法中枚举GC Roots会导致所有Java执行线程停顿。

STW是JVM在后台自动发起和自动完成的。

7.3.4 垃圾回收的并发与并行

并发Concurrent:并不是真正意义上的同时进行,只是CPU将一个时间段划分为几个时间片段,然后在这几个时间区间之间来回切换,由于CPU处理的速度非常快,只要时间间隔处理得当,就可以当用户感受到多个程序同时进行。

image-20210315205934421

并行Parallel:当系统有一个以上的CPU时,一个CPU执行一个进程,另一个CPU执行另一个进程,两个进程互不抢占资源,可以同时进行。决定并行的因素不是CPU数量而是CPU核心数量(一个CPU多核也可以)。

image-20210315210402627

并发是一个时间段同时发生。(多个任务会抢占资源)

并行是一个时间点上同时发生。(不抢占资源)

垃圾回收并发:用户线程与垃圾收集线程同时执行(不一定并行,可能交替执行),垃圾回收线程在执行时不会停顿用户线程的执行。

  • 用户程序在继续执行,而垃圾收集程序线程运行在另一个CPU上
  • CMS、G1

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

7.3.5 安全点与安全区域

安全点:程序执行时并非所有地方都能停顿下来开始GC,只有特定位置才可能停顿下来GC,这些位置为安全点。安全点的选择通常根据“是否具有让程序长时间执行的特征

如何在GC发生时,检查所有线程都跑到最近的安全点安顿下来?

  • 抢先式中断:(不采用了)
  • 主动式中断:设置一个中断标志,各个线程运行到安全点时候主动轮询这个标志,如果中断标志位帧,则自己进行中断挂起。

安全区域:指在一段代码片段中,对象引用关系不发生改变,在这个区域中的任何位置开始GC都是安全的,把这段区域称之为安全区域。

7.3.6 强引用、软引用、弱引用、虚引用和终接器引用

image-20210315213357890

面试题:强引用、软引用、弱引用和虚引用有什么区别?具体使用的场景是什么?

强引用:不回收,软引用:内存不够回收,弱引用:发现即回收,虚引用:对象回收追踪。

强引用 的对象是可触及的,垃圾收集器就永远不回收被引用的对象。相对的,软引用、弱引用和虚引用的对象是软可触及的、弱可触及的和虚可触及的,在一定条件下都是可以被回收的。所以强引用是造成java内存泄漏的主要原因之一

User user=new User(1,"王国富");//强引用

软引用通常用来实现内存敏感的缓存。(高速缓存就用到了软引用)

SoftReference<User> userSoftRef=new SoftReference<User>(new User(1,"王国富"));//软引用对象声明

//上面分解
User user=new User(1,"王国富");
SoftReference<User> userSoftRef=new SoftReference<User>(user);
user=null;//取消强引用

软引用和弱引用非常适合那些可有可无的缓存数据

WeakReference<User> userWeakRef=new WeakReference<User>(new User(1,"王国富"));//弱引用对象声明

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

ReferenceQueue phantomQueue=new ReferenceQueue();
PhantomReference<User> userPhantomRef=new PhantomReference<User>(new User(1,"王国富"),phantomQueue);//虚引用对象声明

终接器引用 FinalReference

用于实现对象的finalize()方法。

7.4 垃圾回收器

7.4.1 评估GC的性能指标

  • 吞吐量:运行用户代码的时间占总运行时间的比例(总运行时间=程序的运行时间+内存回收时间)。
  • 暂停时间(延迟):执行垃圾收集时,程序的工作线程被暂停的时间。
  • 内存占用:Java堆区所占用的内存大小。
  • 垃圾收集开销:吞吐量的补数,垃圾收集所用的时间与总运行时间的比例
  • 收集频率:收集操作发生的频率
  • 快速:一个对象从诞生到被回收所经历的时间。

现代标准:在最大吞吐量优先的情况下,降低停顿时间。

七个经典的垃圾收集器:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eC9oWZKR-1615883123666)(https://i.loli.net/2021/03/16/q7p31tKwWIoEUL9.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lmgNLkwW-1615883123666)(https://i.loli.net/2021/03/16/7johUXPfxm5YAO2.png)]

组合:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mg7Zkmb5-1615883123667)(https://i.loli.net/2021/03/16/BV2XyfwHQkUWdPT.png)]

查看默认的垃圾收集器:

  • -XX: +PrintCommandLineFlags:查看命令行的相关参数(包含使用的垃圾收集器)

  • jinfo -flag 相关垃圾回收器参数 进程ID

JDK6时Parallel GC为Hotspot默认垃圾收集器

JDK9时G1变成默认垃圾收集器,替换CMS,CMS被标记未来会移出(Deprecate)。

JDK11时加入了ZGC垃圾收集器。

JDK14移出了CMS垃圾收集器。

7.4.2 Serial 与 Serial Old垃圾收集器

Serial 垃圾收集器采用复制算法、串行回收和“STW”机制方式执行内存回收,针对于新生代垃圾回收。

Serial Old垃圾收集器同样采用串行回收和STW机制,只不过内存回收算法是标记-整理算法,针对于老年代垃圾回收。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rfIXUmSn-1615883123668)(https://i.loli.net/2021/03/16/4R2eZ8n6IPYX7GS.png)]

这个垃圾收集器只会使用一个CPU或者一个收集线程去完成垃圾收集工作,更重要的是它在进行垃圾收集时必须暂停其他所有的工作线程,直至收集结束。

指定使用:

-XX:+UseSerialGC:表明新生代使用Serial GC,老年代使用Serial Old GC。

7.4.3 ParNew垃圾收集器

ParNew GC是Serial GC的多线程版本,只能处理新生代,采用并行回收复制算法和STW机制。

ParNew GC/SerialOld GC组合:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6iUyOkwL-1615883123668)(https://i.loli.net/2021/03/16/VJ2O17cStRk36Ky.png)]

  • 对于新生代:回收次数多,使用并行方式高效
  • 老年代:回收次数少,使用串行节省资源。

指定使用:-XX:+UseParNewGC表示新生代使用并行收集器,老年代不受影响,还是默认老年代垃圾收集器。

-XX:ParallelGCThreads:限制线程数量,默认开启和CPU数据相同的线程数。

7.4.4 Parallel收集器:吞吐量优先(JDK8默认)

Parallel Scavenge收集器采用复制算法并行回收STW机制

Parallel Scavenge收集器目标是达到一个可控制的吞吐量(也就称之为吞吐量优先的垃圾收集器),自适应调节策略也是Parallel Scavenge收集器与ParNew收集器的重要区别。

高吞吐量可以高效利用CPU时间,尽快完成程序的运算任务,主要适合在后台运算而不需要太多交互的任务,常见的在服务器环境中使用。

Parallel Old收集器采用标记-整理算法并行回收STW机制

jdk8默认垃圾收集器是Parallel收集器。

参数设置

-XX:+UseParallelGC:手动指定新生代垃圾收集器

-XX:+UseParallelOldGC:手动指定老年代垃圾收集器。

上面两个,只要默认开启一个,另一个就会被开启。

-XX:ParallelGCThreads:设置新生代并行收集器的线程数,一般最好与CPU数量相同。

  • 默认情况下:当CPU<=8个,ParallelGCThreads的值等于CPU数量
  • 大于8时,值为3+(5*CPU_Count)/8

-XX:MaxGCPauseMills:设置垃圾收集器的最大停顿时间(ms)

-XX:GCTimeRatio:垃圾收集占用总时间比例(衡量吞吐量大小)(0,100),默认99 (1/(99+1))

-XX:+UseAdaptiveSizePolicy:设置自适应调节策略:达到堆大小、吞吐量和停顿时间的平衡点。

7.4.5 CMS垃圾收集器:低延迟(暂停时间短)(并发)

CMS收集器的关注点是尽可能缩短垃圾收集时用户线程的停顿时间,第一次实现了让垃圾收集器和用户线程同时工作,采用了标记-清除算法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Yx3Wlta2-1615883123669)(https://i.loli.net/2021/03/16/T86SYOmE3LfePlz.png)]

CMS收集器垃圾收集的四个阶段:

  • 初始标记阶段:在这个阶段中,程序中所有的工作线程会STW而暂停,这个阶段的任务:只是标记出GC Roots能直接关联的对象,一旦标记完成,就恢复被暂停的应用程序(直接关联的对象比较小,速度很快
  • 并发标记阶段:从GC Roots直接关联对象开始遍历整个对象图的过程,整个过程耗时很长,并且不停顿用户线程,用户线程与垃圾收集线程一起并发执行。
  • 重新标记阶段修正并发标记期间,因用户线程继续运作而导致标记产生变化的那部分对象的标记记录,这个停顿时间会比初始标记阶段时间稍微长一点。
  • 并发清除阶段:清理除掉标记阶段判断的死亡对象,释放内存。由于不需要移动存在的对象,这个阶段可以并发。

特点:

  • 由于最耗时间的并发标记和并发清除阶段不需要暂停工作,所以整体回收时低停顿的。低延迟
  • CMS在回收的过程中,还应该确保用户线程有足够的内存可用。(设置堆内存使用率的阈值)
  • 使用标记清除算法,会产生内存碎片,为新对象分配内存空间时不能使用指针碰撞技术,只能选择空闲列表执行内存分配。
  • 不能使用标记整理算法的原因:清除与用户线程并发,要是使用整理算法,则对象的地址就发生了改变,导致异常。
  • CMS收集器堆CPU资源非常敏感
  • CMS不能处理浮动垃圾

参数设置

-XX:+UseCMSCompactAtFullCollection:指定在执行完Full GC后堆内存空间进行整理。避免内存碎片产生。

-XX:CMSFullGCsBeforeCompaction:设置执行多少次Full GC后对内存空间进行整理。

-XX:ParallelCMSThreads:设置CMS的线程数量,默认是(ParallelGCThreads+3)/4

-XX:+UseConcMarkSweepGC:手动指定CMS收集器,这样也会自动开启ParNew GC(用于新生代的垃圾收集)

-XX:CMSInitiatingOccupanyFraction设置堆内存使用率的阈值,一旦达到阈值,便开始进行回收。设置该阈值可以有效降低Full GC的执行次数。JDK6以上默认为92%

小结

想要最小化使用内存和并行开销,请选择Serial GC

想要最大化应用程序的吞吐量,选择Parallel GC

如果想最小化GC的中断或停顿时间,请选择CMS GC

7.4.6 G1垃圾收集器(区域化分代式)(JDK9默认使用的垃圾收集器)

G1垃圾收集器的目标是在延迟可控的情况下获得尽可能的高吞吐量。针对新生代和老年代的垃圾收集。

G1 GC有计划的避免在整个java堆中进行全区域的垃圾收集,G1跟踪个region链的垃圾堆积的价值大小(回收所获得的空间大小以及回收所需要的事件的经验值),在后台维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的region

G1垃圾收集器的特点

  • 并发与并行

    • 并行性:G1在回收期间,可以有多个GC线程同时工作,有效利用多核计算能力,此时用户线程STW。
    • 并发性:G1拥有与应用线程交替执行的能力,部分工作可以和应用程序同时执行,因此一般来说,不会在整个回收阶段发生完全堵塞应用和程序的情况。
  • 分代收集

    • G1属于分代型垃圾收集器,他会区分新生代和老年代,新生代有eden区和survivor区。但从堆的结构角度来说,它不要求整个eden、新生代或者老年代都是连续的,也不坚持固定大小和固定数量。
    • 将堆空间分成若干个区域,每个区域包含了逻辑上的新生代和老年代
    • 兼顾对新生代和老年代进行垃圾收集。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8EIORRIU-1615883123670)(https://i.loli.net/2021/03/16/FJCdb3TMYvmsRWK.png)]

  • 空间整合:region之间是复制算法,但整体上是标记整理算法,两种算法都有效的避免了内存碎片。有利于程序长时间运行。

  • 可预测的停顿时间模型

    • G1追踪各个region里面的垃圾堆积的价值大小,在后台维护了一个优先列表,每次根据允许收集时间可以优先收集价值最大的Region,保证G1收集器在有限的时间内可以获取尽可能高的收集效率。
    • 由于分区情况,G1可以只选取部分区域进行内存回收。

小内存应用CMS表现大概率优于G1,而G1在大内存应用上发挥优势,平衡点在6-8G。

参数设置

-XX:+UseG1GC:手动使用G1收集器

-XX:G1HeapRegionSize:设置每个Region的大小。值为2的幂,范围是1MB-32MB之间,目标是根据最小的java堆大小划分出2048个区域。默认是堆内存的1/2000。

-XX:MaxGCPauseMills:设置期望达到最大GC停顿时间指标(JVM尽力实现,但不保证达到),默认值是200ms。

-XX:ParallelGCThreads:设置STW工作线程数的值,最多设置为8

-XX:ConcGCThreads:设置并发标记的线程数。将其设置为并行垃圾回收线程数(ParallelGCThreads)的1/4左右

-XX:InitiatingHeapOccupancyPercent:设置触发并发GC周期的Java堆占用率阈值,超过此值,就触发GC。默认为45。

分区region:化整为零

使用G1收集器时,会将堆内存划分为约2048个大小相同的独立region块,每个region块的大小根据堆内存实际大小而定(1,2,4,8,16,32MB)。所有region大小相同,且在JVM生命周期内不会被改变。

新生代和老年代不在物理隔离,他们都是一部分region(不需要)的集合,通过region的动态分配方式实现逻辑上的连续。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WF9xwujt-1615883123670)(https://i.loli.net/2021/03/16/gLdrPc9JvTU7QNm.png)]

设置H的原因:堆中大对象,默认直接分配到老年代。若是短期存在的大对象,就会对垃圾收集器造成负面影响,因此G1划分了Humongous区,专门存放大对象。如果一个H区装不下一个大对象,则G1会寻找连续H区来存储。G1的大多数行为都把H区作为老年代的一部分来看待。

记忆集Remembered Set

记忆集:一种用来记录从非收集区域指向收集区域的指针集合的抽象数据结构。

G1垃圾回收过程

三个环节:

  • 新生代GC:G1先STW,G1创建回收及,回收机是指被回收的内存分段的集合,新生代回收过程的回收集包含新生代eden区和survivor区所有的内存分段。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nQ4Iu25n-1615883123671)(https://i.loli.net/2021/03/16/EFkyH5lVKihxvTo.png)]

  • 老年代并发标记过程

  • 混合回收:当越来越多的对象晋升为老年代时,为了避免堆内存被耗尽,虚拟机会触发一个混合的垃圾收集器、

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5vOHKgr0-1615883123671)(https://i.loli.net/2021/03/16/7EsODJ4yGAdfz3n.png)]

G1的初衷就是避免Full GC的出现。

7.4.7 ZGC

在尽可能堆吞吐量影响不大的前提下,实现在任意堆内存大小下都可以把垃圾收集的停顿时间限制只在10ms一下的低延迟。

ZGC收集器事是一款基于Region内存布局的,暂时不设分代的,使用了读屏障、染色指针和内存多重映射等技术实现了可并发的标记-整理算法,以低延迟为首要目标的一款垃圾收集器。

工作氛围四个阶段 :

  • 并发标记
  • 并发预备重分配
  • 并发重分配
  • 并发重映射
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值