【Java】JVM 垃圾回收基础

JVM 垃圾回收基础

五竹发布于 1 月 23 日

什么是垃圾

内存中不在被使用到的内存空间,就是垃圾。
Java中的内存是动态分配和自动回收的。学习垃圾收集机制,调优策略,能够帮助我们处理和应对各种工作中面临的内存泄漏问题。

【Java】JVM 垃圾回收基础
Java 虚拟机运行时数据区分为程序计数器、虚拟机栈、本地方法栈、堆、方法区。
其中程序计数器、虚拟机栈、本地方法栈这 3 个区域是线程私有的,会随线程消亡而自动回收,所以不需要管理。
因此垃圾收集只需要关注堆和方法区。

Java的内存分配

堆上分配

  • 如果启动了本地线程分配缓冲,将按线程优先分配在TLAB上。
  • 对象优先在Eden上分配
  • 大对象进入老年代
  • 长期存活的对象进入老年代

栈上分配

基于逃逸分析技术,如果一个对象始终在一个方法内。确定这个对象不会逃逸方法之外,那让这个对象在栈上分配内存,这样对象就会随着方法的结束而自动销毁,降低了垃圾回收的压力。

【Java】JVM 垃圾回收基础

如何判定垃圾

引用计数法

给对象添加一个引用计数器,有对这个对象的引用就对计数加1,引用失效就减1,任何时刻计数器为0的对象就是判定为垃圾。

  • 优点:实现简单,效率高。
  • 缺点:不能解决对象循环引用的问题。在多线程环境下,引用计数变更也要进行昂贵的同步操作,性能较低。

可达性分析法

目前主流的虚拟机才有的算法。他是从根节点(GC Root)向下去搜索对象节点,搜索走过的路径称为引用链,当一个对象到根节点之间没有联通的话,这个对象判定为垃圾。

GC Root对象

可以作为GC Roots的对象包括:

  • 虚拟机栈中引用的对象
  • 方法区类静态属性信用的对象
  • 方法去常量引用的对象
  • 本地方法栈中JNI(Native方法)引用的对象

引用类型

判断一个对象的存活跟引用有关,jdk1.2之前,引用只是指引用类型的数据中存储了另一块内存的地址。jdk1.2之后,java的引用分为以下四种。

  • 强引用:Object obj = new Object();最常见的引用,这样通过new创建的会产生该对象的强引用。只要对象有强引用指向,并且GC Roots可达,那么就不会回收该对象。
  • 软引用: SotfReference类来实现。表示一些还有用但是非必须的对象。在OOM前,垃圾收集器会把这些软引用指向的对象加入回收范围,对于软引用关联的对象,只有在内存不足的时候才会回收。
  • 弱引用:WeakReference,表示非必要对象,在YGC时候会被回收。由于YGC时间不确定,所以弱引用随时都有可能被回收。
  • 虚引用:PhantomReference,无法通过该引用获取指向的对象。在任何时候都可能被垃圾回收器回收。虚引用主要用来跟踪对象被垃圾回收器回收的活动,必须和引用队列配合使用:

ReferenceQueue<String> queue = new ReferenceQueue<>();

PhantomReference<String> phantomReference = new PhantomReference<>("Hello", queue);

当垃圾回收器准备回收一个对象时,发现他有虚引用,就会在回收这对象的内存前,把这个虚引用加入队列,程序通过引用队列中是否有该虚引用,来了解对象是否要被垃圾回收器回收,然后可以在回收前做一些事情。

垃圾收集算法

标记-清除 (Mark-Sweep)

最基础的算法,第一步,先标记,从GC Roots出发,依次标记对象引用关系,然后,将没有被标记的对象清除。
缺点:一个是效率问题,标记和清除两个过程效率都不高;另外,清除过后会产生大量不连续的内存碎片。导致当我们需要分配大对象时候,无法找到足够的连续内存而又触发一次GC。
【Java】JVM 垃圾回收基础

复制(Copy)

复制算法:把内存分为两块大小相同的区域,每次使用其中一块,当使用完了,就把这一块区域上还存活对象拷贝到另一块,然后把这一块清除掉。不会造成内存碎片,但是内存利用率不高,会造成一半的空间浪费。

【Java】JVM 垃圾回收基础

新生代上的对象大多数“朝生夕死”,HotSpot默认将新生代内存划分为一个大的Eden区和两个小的Surivor区。在GC时,将Eden区和一个Surivor区中存活的对象,复制到另外一个Surivor区。Eden区和两个Surivor区比例默认8:1:1,所以这时候只会浪费10%的空间。

标记-整理(Mark-Compact)

和标记清除一样,先标记,但是后续不直接回收对象清理,而是让存活的对象向一端移动,然后直接清理掉端边界之外的内存。
【Java】JVM 垃圾回收基础

由于复制算法在存活对象比较多的时候,效率比较低,且有空间浪费,所以老年代一般会选用标记-整理算法。

### 三种GC算法对比

回收算法优点缺点
标记-清除实现简单存在内存碎片
复制无碎片,性能好内存使用率低
标记-整理无碎片整理过程开销大

分代收集

将上面的各种算法组合在一起,因地制宜。一般我们把堆空间分为新生代和老年代。根据他们的特定采用不同的垃圾回收算法,在新生代,每次GC都会有大量对象死去,少数存活,所以采用复制算法。只用付出少数对象的复制成本,不会造成不连续的内存碎片。而在老年代,对象存活率高,则采用标记整理或者标记清除。

垃圾收集器

术语

  • STW: "Stop The World"简写,也叫全局停顿。会造成服务暂停,没有响应。
  • 串行收集: GC单线程内存回收,会暂停所有的用户线程。比如Serial, Serial Old
  • 并行收集: 多线程进行并发GC,此时暂停用户线程。比如Parallel
  • 并发收集:用户线程和GC线程同时执行,不需要停顿用户线程.适合对响应时间有要求的场景。比如CMS收集器

Serial/Serial Old

Serial是一个单线程的收集器,它只会使用一个CPU或一个收集线程去做垃圾收集,并且在做垃圾收集时需要停止所有的工作线程,知道收集工作结束。Serial停止用户线程,采用复制算法收集年轻代,Serial Old采用标记-整理算法收集老年代。

【Java】JVM 垃圾回收基础

特点:单线程收集,STW

使用 -XX:+UseSerialGC 开启Serial + Serial Old

ParNew

Serial的多线程版本,使用多线程进行垃圾收集。他是新生代的垃圾收集器。需要配合老年代的CMS收集器使用。所以开启需要使用CMS,新生代默认ParNew.

可以通过 ==-XX:ParallelGCThreads== 参数来控制收集的线程数,过程也是STW

Parallel Scavenge/Paraller Old

Parallel Scavenge是新生代的收集器,采用复制算法,多线程的收集器,Paraller Old是老年代收集器,也是多线程收集,采用标记-整理算法。
【Java】JVM 垃圾回收基础

主要参数

  • -XX:UseParallelGC 开启
  • -XX:MaxGCPauseMillis 最大垃圾收集停顿时间
  • -XX:GCTimeRatio 设置吞吐量大小

可控的吞吐量

通过参数 -XX:MaxGCPauseMillis 控制最大GC停顿时间。-XX:GCTimeRatio 设置吞吐量大小

提升吞吐量可以高效利用CPU时间,尽快完成程序任务。

自适应GC策略

处理提供了上面两个参数控制吞吐量大小以外,Parallel Scavenge还可以通过 -XX:+UseAdptiveSizePolicy, 开启指示仪GC策略。打开后,就不再需要手动设置新生代大小,Eden/Surivor比例等参数,虚拟机会根据系统运行状况,动态调整这些参数,从而达到最优的停顿时间,和最高吞吐量。

CMS

  • 1.初始标记:只标记GC Roots能直接关联到的对象,会STW。
  • 2.并发标记:进行GC Roots Tracing的过程,GC线程和用户线程同时执行。
  • 3.重新标记 :修正并发标记期间,因程序运行导致标记发生变化的那些对象。会STW
  • 4.并发清除:并发回收垃圾对象(GC线程和用户线程同时执行)
  • 5.并发重置:清理本次CMS GC上下文信息,为下一次GC做准备。

【Java】JVM 垃圾回收基础

优点:低停顿,并发执行

缺点:

  • 由于并发执行,所以对CPU资源压力大。
  • 无法处理在收集过程中产生的浮动垃圾。
  • 由于采用标记-清除算法,所以会才是大量内存碎片。而导致在需要分配大对象是内存不足,触发FullGC。

使用 -XX:UseConcMarkSweepGC 开启 ParNew+CMS/SerialOld 收集器组合,即新生代采用ParNew,老年代CMS,当CMS出错后,SerialOld备用。
为了解决内存碎片问题,CMS可以通过-XX:+UseCMSCompactAtFullCollection,强制JVM在FullGC完成后对老年代进行压缩,执行碎片整理,同时会STW。想要减少STW次数,可以配置-XX:+CMSFullGCsBeforeCompaction参数,在执行设置的次数后,JVM再在老年代进行空间整理。

JDK9已经将CMS标记为弃用,在JDK14中已经将CMS删除。

G1

JDK7推出的新一代收集器,
是一个面向服务端应用的收集器。相比上面的收集器,
G1作用在整个堆,而其他的收集器都是只作用在新生代或老年代。

G1将Java Heap分割成一些大小相同的Region,通过参数-XX:G1HeapRegionSize指定Region的大小,取值范围为1~32M,应为2的N次幂。G1对每个Region做了分类, 分别包括:Eden,Surivor,Old, Humongous, 其中Humongous相当于一个大的Old,用来存放大对象。

如下图:G1的堆内存布局和传统的堆内存布局不同。
【Java】JVM 垃圾回收基础

G1将空间分成多个区域,跟踪每个区域里面的垃圾堆积的价值大小,构建一个优先列表,优先收集垃圾最多的区域,这也是它为什么叫Garbage-First的原因。

G1与CMS相比的,有何特点

  • 并发与并行:充分的利用多CPU,缩短STW时间。并发标记阶段可与用户线程并发执行,最终标记阶段GC线程可并行执行。
  • 分代收集:G1可以不与其他垃圾收集器配合,独立完成整个GC堆的垃圾收集。
  • 空间整合:G1整体看是采用“标记-整理”算法实现的,局部也有Eden和Surivor Region看上去是采用“复制”算法来实现。整个过程避免了产生内存碎片。
  • 停顿时间可控制:G1除了追求低停顿,还能建立可预测的停顿时间模型,能让用户指定在一个时间段内,消耗在收集上的时间不超过一个时间段。

G1垃圾收集模式

Young GC

  • 1.所有Eden Region都满了时,就会触发Young GC
  • 2.Eden Region里的对象会转移到Surivor Region
  • 3.原Surivor Region中的对象转移到另一个Surivor,或者晋升到Old Region
  • 4.空闲Region会被放入空闲列表,等待下次使用。

Mixed GC

当老年代占整个Heap的大小百分比达到一个阀值(-XX:InitialingHeapOccupancyPercent)时,默认45%,就会触发Mixed GC,
收集整个新生代以及部分老年代。

Mixed GC 回收过程

【Java】JVM 垃圾回收基础

  • 1.初始标记:只标记GC Roots能关联到的对象。修改TAMS的值,此阶段会STW.
  • 2.并发标记: 从GC Root开始对堆内存中的对象进行可达性分析,找出存活的对象,此过程可以和用户线程并发执行。
  • 3.最终标记:修正在并发标记阶段用户线程继续运行导致标记产生变动的记录。此过程STW,但是可以并行执行。
  • 4.筛选回收:对各个Region的回收价值和成本进行排序,根据用户期望的停顿时间制定回收计划。

Full GC

当复制对象内存不够时,或无法分配足够空间时,触发Full GC
Full GC模式是采用Serial Old收集的,所以会STW。

如何减少Full GC?

  • 增大-XX:G1ReserverPercent,来增加预留内存。
  • 减少 -XX:InitialingHeapOccupancyPercent,当老年代达到这个值是就触发Mixed GC,
  • 增加 -XX:ConcGCThreads 并发阶段的线程数。

总结

对以上介绍的垃圾回收器总结

  • Serial 串行,作用于新生代,采用复制算法
  • ParNew 并行,作用于新生代,采用复制算法
  • Serial Old 串行,作用于老年代,标记-整理算法
  • Parallel 并行, 作用于新生代, 复制算法
  • Parallel Old 并行, 作用于老年代, 标记-整理算法
  • CMS 并发, 作用于老年代, 标记-清除算法
  • G1 并发+并行, 作用于整个堆,复制算法,标记-整理

参考资料

《深入理解Java虚拟机 JVM高级特性与最佳实践》

javajvmgc

阅读 12发布于 1 月 23 日

本作品系原创,采用《署名-非商业性使用-禁止演绎 4.0 国际》许可协议

avatar

五竹

1 声望

0 粉丝

0 条评论

得票时间

avatar

五竹

1 声望

0 粉丝

宣传栏

什么是垃圾

内存中不在被使用到的内存空间,就是垃圾。
Java中的内存是动态分配和自动回收的。学习垃圾收集机制,调优策略,能够帮助我们处理和应对各种工作中面临的内存泄漏问题。

【Java】JVM 垃圾回收基础
Java 虚拟机运行时数据区分为程序计数器、虚拟机栈、本地方法栈、堆、方法区。
其中程序计数器、虚拟机栈、本地方法栈这 3 个区域是线程私有的,会随线程消亡而自动回收,所以不需要管理。
因此垃圾收集只需要关注堆和方法区。

Java的内存分配

堆上分配

  • 如果启动了本地线程分配缓冲,将按线程优先分配在TLAB上。
  • 对象优先在Eden上分配
  • 大对象进入老年代
  • 长期存活的对象进入老年代

栈上分配

基于逃逸分析技术,如果一个对象始终在一个方法内。确定这个对象不会逃逸方法之外,那让这个对象在栈上分配内存,这样对象就会随着方法的结束而自动销毁,降低了垃圾回收的压力。

【Java】JVM 垃圾回收基础

如何判定垃圾

引用计数法

给对象添加一个引用计数器,有对这个对象的引用就对计数加1,引用失效就减1,任何时刻计数器为0的对象就是判定为垃圾。

  • 优点:实现简单,效率高。
  • 缺点:不能解决对象循环引用的问题。在多线程环境下,引用计数变更也要进行昂贵的同步操作,性能较低。

可达性分析法

目前主流的虚拟机才有的算法。他是从根节点(GC Root)向下去搜索对象节点,搜索走过的路径称为引用链,当一个对象到根节点之间没有联通的话,这个对象判定为垃圾。

GC Root对象

可以作为GC Roots的对象包括:

  • 虚拟机栈中引用的对象
  • 方法区类静态属性信用的对象
  • 方法去常量引用的对象
  • 本地方法栈中JNI(Native方法)引用的对象

引用类型

判断一个对象的存活跟引用有关,jdk1.2之前,引用只是指引用类型的数据中存储了另一块内存的地址。jdk1.2之后,java的引用分为以下四种。

  • 强引用:Object obj = new Object();最常见的引用,这样通过new创建的会产生该对象的强引用。只要对象有强引用指向,并且GC Roots可达,那么就不会回收该对象。
  • 软引用: SotfReference类来实现。表示一些还有用但是非必须的对象。在OOM前,垃圾收集器会把这些软引用指向的对象加入回收范围,对于软引用关联的对象,只有在内存不足的时候才会回收。
  • 弱引用:WeakReference,表示非必要对象,在YGC时候会被回收。由于YGC时间不确定,所以弱引用随时都有可能被回收。
  • 虚引用:PhantomReference,无法通过该引用获取指向的对象。在任何时候都可能被垃圾回收器回收。虚引用主要用来跟踪对象被垃圾回收器回收的活动,必须和引用队列配合使用:

ReferenceQueue<String> queue = new ReferenceQueue<>();

PhantomReference<String> phantomReference = new PhantomReference<>("Hello", queue);

当垃圾回收器准备回收一个对象时,发现他有虚引用,就会在回收这对象的内存前,把这个虚引用加入队列,程序通过引用队列中是否有该虚引用,来了解对象是否要被垃圾回收器回收,然后可以在回收前做一些事情。

垃圾收集算法

标记-清除 (Mark-Sweep)

最基础的算法,第一步,先标记,从GC Roots出发,依次标记对象引用关系,然后,将没有被标记的对象清除。
缺点:一个是效率问题,标记和清除两个过程效率都不高;另外,清除过后会产生大量不连续的内存碎片。导致当我们需要分配大对象时候,无法找到足够的连续内存而又触发一次GC。
【Java】JVM 垃圾回收基础

复制(Copy)

复制算法:把内存分为两块大小相同的区域,每次使用其中一块,当使用完了,就把这一块区域上还存活对象拷贝到另一块,然后把这一块清除掉。不会造成内存碎片,但是内存利用率不高,会造成一半的空间浪费。

【Java】JVM 垃圾回收基础

新生代上的对象大多数“朝生夕死”,HotSpot默认将新生代内存划分为一个大的Eden区和两个小的Surivor区。在GC时,将Eden区和一个Surivor区中存活的对象,复制到另外一个Surivor区。Eden区和两个Surivor区比例默认8:1:1,所以这时候只会浪费10%的空间。

标记-整理(Mark-Compact)

和标记清除一样,先标记,但是后续不直接回收对象清理,而是让存活的对象向一端移动,然后直接清理掉端边界之外的内存。
【Java】JVM 垃圾回收基础

由于复制算法在存活对象比较多的时候,效率比较低,且有空间浪费,所以老年代一般会选用标记-整理算法。

### 三种GC算法对比

回收算法优点缺点
标记-清除实现简单存在内存碎片
复制无碎片,性能好内存使用率低
标记-整理无碎片整理过程开销大

分代收集

将上面的各种算法组合在一起,因地制宜。一般我们把堆空间分为新生代和老年代。根据他们的特定采用不同的垃圾回收算法,在新生代,每次GC都会有大量对象死去,少数存活,所以采用复制算法。只用付出少数对象的复制成本,不会造成不连续的内存碎片。而在老年代,对象存活率高,则采用标记整理或者标记清除。

垃圾收集器

术语

  • STW: "Stop The World"简写,也叫全局停顿。会造成服务暂停,没有响应。
  • 串行收集: GC单线程内存回收,会暂停所有的用户线程。比如Serial, Serial Old
  • 并行收集: 多线程进行并发GC,此时暂停用户线程。比如Parallel
  • 并发收集:用户线程和GC线程同时执行,不需要停顿用户线程.适合对响应时间有要求的场景。比如CMS收集器

Serial/Serial Old

Serial是一个单线程的收集器,它只会使用一个CPU或一个收集线程去做垃圾收集,并且在做垃圾收集时需要停止所有的工作线程,知道收集工作结束。Serial停止用户线程,采用复制算法收集年轻代,Serial Old采用标记-整理算法收集老年代。

【Java】JVM 垃圾回收基础

特点:单线程收集,STW

使用 -XX:+UseSerialGC 开启Serial + Serial Old

ParNew

Serial的多线程版本,使用多线程进行垃圾收集。他是新生代的垃圾收集器。需要配合老年代的CMS收集器使用。所以开启需要使用CMS,新生代默认ParNew.

可以通过 ==-XX:ParallelGCThreads== 参数来控制收集的线程数,过程也是STW

Parallel Scavenge/Paraller Old

Parallel Scavenge是新生代的收集器,采用复制算法,多线程的收集器,Paraller Old是老年代收集器,也是多线程收集,采用标记-整理算法。
【Java】JVM 垃圾回收基础

主要参数

  • -XX:UseParallelGC 开启
  • -XX:MaxGCPauseMillis 最大垃圾收集停顿时间
  • -XX:GCTimeRatio 设置吞吐量大小

可控的吞吐量

通过参数 -XX:MaxGCPauseMillis 控制最大GC停顿时间。-XX:GCTimeRatio 设置吞吐量大小

提升吞吐量可以高效利用CPU时间,尽快完成程序任务。

自适应GC策略

处理提供了上面两个参数控制吞吐量大小以外,Parallel Scavenge还可以通过 -XX:+UseAdptiveSizePolicy, 开启指示仪GC策略。打开后,就不再需要手动设置新生代大小,Eden/Surivor比例等参数,虚拟机会根据系统运行状况,动态调整这些参数,从而达到最优的停顿时间,和最高吞吐量。

CMS

  • 1.初始标记:只标记GC Roots能直接关联到的对象,会STW。
  • 2.并发标记:进行GC Roots Tracing的过程,GC线程和用户线程同时执行。
  • 3.重新标记 :修正并发标记期间,因程序运行导致标记发生变化的那些对象。会STW
  • 4.并发清除:并发回收垃圾对象(GC线程和用户线程同时执行)
  • 5.并发重置:清理本次CMS GC上下文信息,为下一次GC做准备。

【Java】JVM 垃圾回收基础

优点:低停顿,并发执行

缺点:

  • 由于并发执行,所以对CPU资源压力大。
  • 无法处理在收集过程中产生的浮动垃圾。
  • 由于采用标记-清除算法,所以会才是大量内存碎片。而导致在需要分配大对象是内存不足,触发FullGC。

使用 -XX:UseConcMarkSweepGC 开启 ParNew+CMS/SerialOld 收集器组合,即新生代采用ParNew,老年代CMS,当CMS出错后,SerialOld备用。
为了解决内存碎片问题,CMS可以通过-XX:+UseCMSCompactAtFullCollection,强制JVM在FullGC完成后对老年代进行压缩,执行碎片整理,同时会STW。想要减少STW次数,可以配置-XX:+CMSFullGCsBeforeCompaction参数,在执行设置的次数后,JVM再在老年代进行空间整理。

JDK9已经将CMS标记为弃用,在JDK14中已经将CMS删除。

G1

JDK7推出的新一代收集器,
是一个面向服务端应用的收集器。相比上面的收集器,
G1作用在整个堆,而其他的收集器都是只作用在新生代或老年代。

G1将Java Heap分割成一些大小相同的Region,通过参数-XX:G1HeapRegionSize指定Region的大小,取值范围为1~32M,应为2的N次幂。G1对每个Region做了分类, 分别包括:Eden,Surivor,Old, Humongous, 其中Humongous相当于一个大的Old,用来存放大对象。

如下图:G1的堆内存布局和传统的堆内存布局不同。
【Java】JVM 垃圾回收基础

G1将空间分成多个区域,跟踪每个区域里面的垃圾堆积的价值大小,构建一个优先列表,优先收集垃圾最多的区域,这也是它为什么叫Garbage-First的原因。

G1与CMS相比的,有何特点

  • 并发与并行:充分的利用多CPU,缩短STW时间。并发标记阶段可与用户线程并发执行,最终标记阶段GC线程可并行执行。
  • 分代收集:G1可以不与其他垃圾收集器配合,独立完成整个GC堆的垃圾收集。
  • 空间整合:G1整体看是采用“标记-整理”算法实现的,局部也有Eden和Surivor Region看上去是采用“复制”算法来实现。整个过程避免了产生内存碎片。
  • 停顿时间可控制:G1除了追求低停顿,还能建立可预测的停顿时间模型,能让用户指定在一个时间段内,消耗在收集上的时间不超过一个时间段。

G1垃圾收集模式

Young GC

  • 1.所有Eden Region都满了时,就会触发Young GC
  • 2.Eden Region里的对象会转移到Surivor Region
  • 3.原Surivor Region中的对象转移到另一个Surivor,或者晋升到Old Region
  • 4.空闲Region会被放入空闲列表,等待下次使用。

Mixed GC

当老年代占整个Heap的大小百分比达到一个阀值(-XX:InitialingHeapOccupancyPercent)时,默认45%,就会触发Mixed GC,
收集整个新生代以及部分老年代。

Mixed GC 回收过程

【Java】JVM 垃圾回收基础

  • 1.初始标记:只标记GC Roots能关联到的对象。修改TAMS的值,此阶段会STW.
  • 2.并发标记: 从GC Root开始对堆内存中的对象进行可达性分析,找出存活的对象,此过程可以和用户线程并发执行。
  • 3.最终标记:修正在并发标记阶段用户线程继续运行导致标记产生变动的记录。此过程STW,但是可以并行执行。
  • 4.筛选回收:对各个Region的回收价值和成本进行排序,根据用户期望的停顿时间制定回收计划。

Full GC

当复制对象内存不够时,或无法分配足够空间时,触发Full GC
Full GC模式是采用Serial Old收集的,所以会STW。

如何减少Full GC?

  • 增大-XX:G1ReserverPercent,来增加预留内存。
  • 减少 -XX:InitialingHeapOccupancyPercent,当老年代达到这个值是就触发Mixed GC,
  • 增加 -XX:ConcGCThreads 并发阶段的线程数。

总结

对以上介绍的垃圾回收器总结

  • Serial 串行,作用于新生代,采用复制算法
  • ParNew 并行,作用于新生代,采用复制算法
  • Serial Old 串行,作用于老年代,标记-整理算法
  • Parallel 并行, 作用于新生代, 复制算法
  • Parallel Old 并行, 作用于老年代, 标记-整理算法
  • CMS 并发, 作用于老年代, 标记-清除算法
  • G1 并发+并行, 作用于整个堆,复制算法,标记-整理

参考资料

《深入理解Java虚拟机 JVM高级特性与最佳实践》

以上是 【Java】JVM 垃圾回收基础 的全部内容, 来源链接: utcz.com/a/107263.html

回到顶部