首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >【JVM】垃圾回收算法 && 垃圾回收器 && 一个对象的生命周期

【JVM】垃圾回收算法 && 垃圾回收器 && 一个对象的生命周期

原创
作者头像
lirendada
发布2026-04-26 08:48:39
发布2026-04-26 08:48:39
380
举报
文章被收录于专栏:JavaJava

垃圾回收 GC

垃圾回收机制JVM 自动管理内存的一种能力,主要负责清除不再使用的对象,从而避免内存泄漏或溢出。其目标就是:

  • 回收不再被引用的对象(以对象为单位进行回收)
  • 清理内存空间
  • 保证程序长期运行的稳定性

垃圾回收主要是在 方法区 中执行,其它的内存区域不需要回收,如下表所示:

内存区域

是否 GC 管理

是否参与回收

✅ 是

✅ 主要回收对象分配区域

方法区(元空间)

✅ 是

✅ 常量池、类型信息、静态变量

虚拟机栈/本地方法栈/程序计数器

❌ 否

❌ 线程执行过程中自动回收

一、哪些对象应该被回收❓❓❓

① 引用计数算法(已被淘汰)

每个对象都有一个引用计数器,每当有一个地方引用它,计数器就加一;每当引用失效时,则计数器就减一;只要计数器为 0,则说明该对象不再被使用,此时就回收该对象!

引用计数法实现简单,判定效率也比较高,在大部分情况下都是一个不错的算法。比如 Swift 就采用该算法进行内存管理。

缺点如下所示:

  1. 需要额外的内存存储引用计数
  2. 存在循环引用的问题
代码语言:javascript
复制
class Test {
    Test t;
}

Test a = new Test();
Test b = new Test();
a.t = b;
b.t = a;

// 下面将a、b变成null之后,由于内部的t还存在各自的引用,等待对方释放,但是又不释放自己的引用
// 就造成了循环引用问题,导致内存泄漏
a = null;
b = null;

② 可达性分析法(Reachability Analysis)⭐⭐⭐

可达性分析法是 Java 采用的判断对象是否需要回收的算法!

原理:从一组叫作 GC Roots 的节点出发,向下搜索对象引用链。如果对象不能通过任何路径被 GC Roots 到达,就认为它 "不可达",则可被回收。

这种方法不会出现循环引用的问题,但相比引用计数算法来说,时间开销会大一些,因为需要遍历这颗树来判断可达性!

GC Roots 包括:

  1. 虚拟机栈中的引用:当前线程栈帧里的局部变量
  2. 方法区中的静态变量:static 引用的对象
  3. 方法区中的常量:常量池中的引用
  4. 本地方法栈(JNI)中的引用
  5. 正在运行的线程对象本身
  6. JVM 内部保留的对象
    1. 如 Class 对象、异常对象等

二、垃圾回收算法

通过上面确认了哪些对象应该被回收之后,就要进行垃圾对象的回收了!

下面是常见的垃圾回收算法:

算法

简介

适用场景

复制算法

把活的对象从一块复制到另一块

新生代,效率高

标记-清除

标记存活对象,清除未标记对象

老年代

标记-整理

清除后移动存活对象,解决碎片

老年代

分代收集

结合上面其它算法,按对象生命周期长短分类处理

JVM 默认策略

① 标记-清除算法

标记-清除算法是最基础的回收算法,后续回收算法都是基于该算法进行改进的。

原理:首先标记所有需要回收的对象,然后在统一标记完成后回收所有被标记的对象。

缺点:① 会造成大量内存碎片,降低内存利用率。

② 标记和清除的过程效率不高

② 复制算法

"复制算法" 的出现是为了解决 "标记-清除算法" 的内存碎片问题。

原理:将内存空间分为大小相等的两块,每次只使用其中的一块。当这块内存需要进行垃圾回收时,会将此区域中还存活的对象复制到另一块内存中,然后再把当前内存块进行清除。

优点:避免了内存碎片问题

缺点:① 浪费了大量内存空间

② 如果存活对象非常多的话,复制开销会很大

现在的商用虚拟机(包括 HotSpot)都是采用 复制算法 来 回收新生代! 新生代中 98% 的对象都是 "朝生夕死" 的,所以并不需要按照 1:1 的比例来划分内存空间,而是将新生代内存分为一块较大的 Eden 空间(伊甸园)和两块较小的 Survivor 空间(幸存者),每次使用 Eden 和其中一块 Survivor(两个 Survivor 区域一个称为 From 区,另一个称为 To 区域)。 当回收时,将 EdenSurvivor 中还存活的对象一次性复制到另一块 Survivor 空间上,最后清理掉 Eden 和刚才用过的 Survivor 空间。 当 Survivor 空间不够用时,需要依赖老年代内存进行分配担保。 HotSpot 默认 EdenSurvivor 的大小比例是 8:1,也就是说 Eden:From:To = 8:1:1。所以每次新生代可用内存空间为整个新生代容量的 90%,而剩下的 10% 用来存放回收后存活的对象。 HotSpot 实现的复制算法流程如下:

  1. Eden 区满的时候,会触发第一次 MinorGC,把还活着的对象拷贝到 Survivor From 区;
  2. Eden 区再次触发 MinorGC 的时候,会扫描 Eden 区和 From 区域,对两个区域进行垃圾回收,经过这次回收后还存活的对象,则直接复制到 To 区域,并将 EdenFrom 区域清空。
  3. 当后续 Eden 又发生 MinorGC 时,会对 EdenTo 区域进行垃圾回收,存活的对象复制到 From 区域,并将 EdenTo 区域清空。
  4. 部分对象会在 FromTo 区域中复制来复制去,如此交换 15 次(由 JVM 参数 MaxTenuringThreshold 决定,这个参数默认是 15),最终如果还是存活,就存入到老年代。

③ 标记-整理算法

由于 "复制算法" 的拷贝操作在对象存活率比较高的时候开销很大,效率会很低,所以老年代不能采用 "复制算法",而是针对 老年代 的特点,采用 "标记-整理算法"。

原理:标记过程和 "标记-清除算法" 是一样的,不同在于 "标记-整理算法" 不是直接对可回收对象进行清除,而是采用类似压缩数组元素的方式,把所有存活对象都往一侧移动,然后直接清除掉端边界以外的内存。

优点:① 避免了内存碎片问题

避免了 "复制算法" 中了内存浪费问题

缺点:搬运对象的开销大

④ 分代算法

分代算法实际上只是做了一个分区,把内存空间划分为新生代、老年代,然后针对两者采用不同的回收算法处理,目前大部分的 JVM 垃圾回收都采用了这种思想!

新生代 中每次垃圾回收都有大批对象死去,只有少量存活,因此我们采用 "复制算法"。

老年代 中对象存活率高、没有额外空间对它进行分配担保,就必须采用 "标记-清理" 或者 "标记-整理" 算法。

  1. Minor GC(新生代 GC)
    1. 指发生在新生代的垃圾收集。由于 Java 对象大多具有 "朝生夕灭" 的特性,Minor GC 发生得非常频繁。新生代通常采用 复制算法 进行回收,只需要处理少量存活对象,因此 回收速度较快,停顿时间相对较短
  2. Full GC(全堆 GC)
    1. 指对 整个 Java 堆(包括新生代和老年代),并且通常还包括方法区(Metaspace)进行的垃圾收集。Full GC 往往由老年代空间不足、Metaspace 不足或并发回收失败等原因触发。
    2. 一次 Full GC 通常会伴随 Stop-The-World,其执行时间显著长于 Minor GC,在生产环境中应尽量避免频繁发生
    3. Full GC 并没有固定算法,具体取决于垃圾回收器实现。
      • 在传统的 Serial OldParallel Old 中,Full GC 通常采用 标记-整理 算法,以避免老年代内存碎片。
      • CMS 在正常回收阶段使用 标记-清除,但并发失败后会退化为基于 标记-整理Full GC
      • G1Full GC 是兜底机制,同样采用 标记-整理,但性能较差,因此生产环境应尽量避免。

原理大概如下所示:

  1. 堆内存为两个区:新生代、老年代
  2. 新生代默认占堆内存的 1/3,老年代默认占堆内存的 2/3
  3. 新生代又分为 Eden 区、Survivor From 区、Survivor To 区默认比例是 8:1:1
  4. 工作过程:
    1. 所有新创建的对象都在 Eden 区,当 Eden 区内存满后将 Eden 区和 Survivor From 区存活的对象复制到 Survivor To区;
    2. 清空 Eden 区与 Survivor From 区;
    3. 同时 Survivor FromSurvivor To 分区进行交换;
    4. 每次 Minor GC 存活对象年龄加 1,当年龄达到 15(默认值)岁时,被移到老年代;
    5. Eden 的空间无法容纳新创建的对象时,这些对象直接被移至老年代;
    6. 当老年代空间占用达到阈值时,触发 Major GC
    7. 以上流程循环执行。

三、垃圾回收器

如果说上面我们讲的收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现

垃圾收集器的作用:垃圾收集器是为了保证程序能够正常、持久运行的一种技术,它是将程序中不用的死亡对象也就是垃圾对象进行清除,从而保证了新对象能够正常申请到内存空间。

以下这些收集器是 HotSpot 虚拟机随着不同版本推出的重要的垃圾收集器:

上图展示了七种作用于不同分代的收集器,如果两个收集器之间存在连线,就说明他们之间可以搭配使用。所处的区域,表示它是属于新生代收集器还是老年代收集器。

自从有了 Java,就有了垃圾收集器,这么多垃圾收集器其实是历史发展的产物。最早的垃圾收集器为 Serial,也就是串行执行的垃圾收集器,SerialOld 为串行的老年代收集器,而随着时间的发展,为了提升更高的性能,于是有了 Serial 多线程版的垃圾收集器 ParNew。后来人们想要更高吞吐量的垃圾收集器,吞吐量是指单位时间内成功回收垃圾的数量,于是就有了吞吐量优先的垃圾收集器 ParallelScavenge(吞吐量优先的新生代垃圾收集器)和 ParallelOld(吞吐量优先的老年代垃圾收集器)。随着技术的发展后来又有了 CMSConcurrentMarkSweep)垃圾收集器,CMS 可以兼顾吞吐量和以获取最短回收停顿时间为目标的收集器,在 JDK1.8 之前 BS 系统的主流垃圾收集器,而在 JDK1.8 之后,出现了第一个既不完全属于新生代也不完全属于老年代的垃圾收集器 G1GarbageFirst),G1 提供了基本不需要停止程序就可以收集垃圾的技术

① Serial(新生代收集器,串行GC)

Serial 收集器是最基本、发展历史最悠久的收集器,在 JDK1.3.1 之前是虚拟机新生代收集的唯一选择。

这个收集器是一个单线程的收集器,但它的 "单线程" 的意义并不仅仅说明它只会使用一个 CPU 或一条收集线程去完成垃圾收集工作,更重要的是在它进行垃圾收集时,必须暂停其他所有的工作线程,直到它收集结束(Stop The World,译为停止整个程序,简称 STW)。

优势:采用 复制算法,简单而高效(与其他收集器的单线程比),对于限定单个 CPU 的环境来说,Serial 收集器由于没有线程交互的开销,专心做垃圾收集自然可以获得最高的单线程收集效率。实际上到现在为止:它依然是虚拟机运行在 Client 模式下的默认新生代收集器。

② ParNew(新生代收集器,并行GC)

ParNew 收集器是 Serial 收集器的多线程版本,除了使用多条线程进行垃圾收集之外,其余行为包括 Serial 收集器可用的所有控制参数、收集算法、STW、对象分配规则、回收策略等都与 Serial 收集器完全一样,在实现上,这两种收集器也共用了相当多的代码。

ParNew 收集器是许多运行在 Server 模式下的虚拟机中首选的新生代收集器。作为 Server 的首选收集器之中有一个与性能无关的很重要的原因是:除了 Serial 收集器外,目前只有它能与 CMS 收集器配合工作。

JDK1.5 时期,HotSpot 推出了一款在强交互应用中几乎可认为有划时代意义的垃圾收集器:CMS 收集器,这款收集器是 HotSpot 虚拟机中第一款真正意义上的并发收集器,它第一次实现了让垃圾收集线程与用户线程同时工作。 不幸的是,CMS 作为老年代的收集器,却无法与 JDK1.4.0 中已经存在的新生代收集器 Parallel Scavenge 配合工作,所以在 JDK1.5 中使用 CMS 来收集老年代的时候,新生代只能选择 ParNew 或者 Serial 收集器中的一个。

Serial 收集器对比,ParNew 收集器在单 CPU 的环境中绝对不会有比 Serial 收集器更好的效果,甚至由于存在线程交互的开销,该收集器在通过超线程技术实现的两个 CPU 的环境中都不能百分之百地保证可以超越 Serial 收集器。然而,随着可以使用的 CPU 的数量的增加,它对于 GC 时系统资源的有效利用还是很有好处的。

③ Parallel Scavenge(新生代收集器,并行GC)

Parallel Scavenge 收集器是一个新生代收集器,它也是使用 复制算法 的收集器,也是并行的多线程收集器。它使用两个参数来控制吞吐量:

代码语言:javascript
复制
XX:MaxGCPauseMillis 控制最大的垃圾收集停顿时间
XX:GCRatio          直接设置吞吐量的大小

直观上,只要最大的垃圾收集停顿时间越小,吞吐量就越高,但是 GC 停顿时间的缩短是以牺牲吞吐量和新生代空间作为代价的。比如原来 10s 收集一次,每次停顿 100ms,现在变成 5s 收集一次,每次停顿 70ms。停顿时间下降的同时,吞吐量也下降了。

应用场景:停顿时间越短就越适合需要与用户交互的程序,良好的响应速度能提升用户体验;而高吞吐量则可以高效率地利用 CPU 时间,尽快完成程序的运算任务,主要适合在后台运算而不需要太多交互的任务。

它和其它收集器的对比如下所示:

  1. Parallel ScavengeCMS 等收集器:
    1. ParallelScavenge 收集器的特点是它的关注点与其他收集器不同,CMS 等收集器的关注点是尽可能地缩短垃圾收集时用户线程的停顿时间,而 ParallelScavenge 收集器的目标则是达到一个可控制的吞吐量。由于与吞吐量关系密切,ParallelScavenge 收集器也经常称为 "吞吐量优先" 收集器。
  2. Parallel ScavengeParNew 收集器:
    1. ParallelScavenge 收集器与 ParNew 收集器的一个重要区别是它具有自适应调节策略。

    GC 自适应的调节策略: Parallel Scavenge 收集器有一个参数 -XX:+UseAdaptiveSizePolicy。当这个参数打开之后,就不需要手工指定新生代的大小、EdenSurvivor 区的比例、晋升老年代对象年龄等细节参数了,JVM 会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或者最大的吞吐量,这种调节方式称为 GC 自适应的调节策略。

④ Serial Old(老年代收集器,串行GC)

Serial OldSerial 收集器的老年代版本,它同样是一个单线程收集器,使用 "标记-整理" 算法。应用场景如下所示:

  1. Client 模式:Serial Old 收集器的主要意义也是在于给 Client 模式下的虚拟机使用。
  2. Server 模式:如果是 Server 模式,那么它主要还有两大用途:一种用途是在 JDK1.5 以及之前的版本中与 Parallel Scavenge 收集器搭配使用,另一种用途就是作为 CMS 收集器的后备预案,在并发收集发生 Concurrent Mode Failure 时使用。

⑤ Parallel Old(老年代收集器,并行GC)

Parallel OldParallel Scavenge 收集器的老年代版本使用多线程"标记-整理" 算法。

应用场景:在注重吞吐量以及 CPU 资源敏感的场合,都可以优先考虑 Parallel Scavenge 配合 Parallel Old收集器。

这个收集器是在 JDK1.6 中才开始提供的,在此之前,新生代的 Parallel Scavenge 收集器一直处于比较尴尬的状态。原因是,如果新生代选择了 Parallel Scavenge 收集器,老年代除了 Serial Old 收集器外别无选择(Parallel Scavenge 收集器无法与 CMS 收集器配合工作)。由于老年代 SerialOld 收集器在服务端应用性能上表现不佳,使用了 Parallel Scavenge 收集器也未必能在整体应用上获得吞吐量最大化的效果,由于单线程的老年代收集中无法充分利用服务器多 CPU 的处理能力,在老年代很大而且硬件比较高级的环境中,这种组合的吞吐量甚至还不一定有 ParNewCMS 的组合给力。直到 Parallel Old 收集器出现后,"吞吐量优先" 收集器终于有了比较名副其实的应用组合。

⑥ CMS(老年代收集器,并发GC)⭐⭐⭐

CMSConcurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。目前很大一部分的 Java 应用集中在互联网站或者 B/S 系统的服务端上,这类应用尤其重视服务的响应速度,希望系统停顿时间最短,以给用户带来较好的体验,而 CMS 收集器就非常符合这类应用的需求!

CMS 收集器是基于 "标记-清除" 算法实现的,它的运作过程相对于前面几种收集器来说更复杂一些,整个过程分为四个步骤:

  1. 初始标记:仅仅只是标记一下 GCRoots 能直接关联到的对象,速度很快,需要 Stop The World
  2. 并发标记:进行 GCRoots Tracing 的过程。
  3. 重新标记:为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比 初始标记 阶段稍长一些,但远比 并发标记 的时间短。仍然需要 Stop The World
  4. 并发清除:清除对象。

由于整个过程中耗时最长的 并发标记并发清除 过程收集器线程都可以与用户线程一起工作,所以从总体上来说,CMS 收集器的内存回收过程是与用户线程一起并发执行的

优点:并发回收低停顿

缺点:

  1. CMS 收集器对 CPU 资源非常敏感
    1. 其实面向并发设计的程序都对 CPU 资源比较敏感。在并发阶段,它虽然不会导致用户线程停顿,但是会因为占用了一部分线程(或者说 CPU 资源)而导致应用程序变慢,总吞吐量会降低。
    2. CMS 默认启动的回收线程数是 (CPU数量+3)/4,也就是当 CPU 在四个以上时,并发回收时垃圾收集线程不少于 25%CPU 资源,并且随着 CPU 数量的增加而下降。但是当 CPU 不足四个时,CMS 对用户程序的影响就可能变得很大。
  2. CMS 收集器无法处理浮动垃圾
    1. CMS 收集器无法处理浮动垃圾,可能出现 ConcurrentModeFailure 失败而导致另一次 FullGC 的产生。
    2. 由于 CMS 并发清理阶段用户线程还在运行着,伴随程序运行自然就还会有新的垃圾不断产生,这一部分垃圾出现在标记过程之后,CMS 无法在当次收集中处理掉它们,只好留待下一次 GC 时再清理掉。这一部分垃圾就称为 "浮动垃圾"。
    3. 也是由于在垃圾收集阶段用户线程还需要运行,那也就还需要预留有足够的内存空间给用户线程使用,因此CMS 收集器不能像其他收集器那样等到老年代几乎完全被填满了再进行收集,需要预留一部分空间提供并发收集时的程序运作使用。
    4. 要是 CMS 运行期间预留的内存无法满足程序需要,就会出现一次 ConcurrentModeFailure 失败,这时虚拟机将启动后备预案:临时启用 SerialOld 收集器来重新进行老年代的垃圾收集,这样停顿时间就很长了。
  3. CMS 收集器会产生大量空间碎片
    1. CMS 是一款基于 "标记-清除" 算法实现的收集器,这意味着收集结束时会有大量空间碎片产生。空间碎片过多时,将会给大对象分配带来很大麻烦,往往会出现老年代还有很大空间剩余,但是无法找到足够大的连续空间来分配当前对象,不得不提前触发一次 FullGC

⑦ G1(唯一的全区域垃圾收集器)⭐⭐⭐

G1Garbage First)垃圾回收器是用在堆内存很大的情况下,将堆划分为多个 Region,通过收益优先回收垃圾最多的区域。它支持并发标记和混合回收,显著减少 Full GC 的触发和停顿时间。

新生代使用 复制算法,老年代采用 标记-整理Mixed GC 回收 young + 部分 old,实现可预测停顿时间,是服务器端长时间运行应用的默认 GC。

设计理念

  • 不再严格分代(虽然仍有 young/old 概念)
  • 按 Region 划分堆 → 可以回收 "收益最大" 的区域
  • 主要解决老年代 GC 导致 Full GC 的问题

G1 垃圾回收器回收 region 的时候基本不会 STW,而是基于 most garbage 优先回收的策略来对 region 进行垃圾回收的。(整体来看是基于 "标记-整理" 算法,从局部来看也就是两个 region 之间则是基于 "复制" 算法)

无论如何,G1 收集器采用的算法都意味着一个 region 有可能属于 EdenSurvivor 或者 Tenured 内存区域。

图中的 E 表示该 region 属于 Eden 内存区域,S 表示属于 Survivor 内存区域,T 表示属于 Tenured 内存区域,空白的表示未使用的内存空间。

G1 垃圾收集器还增加了一种新的内存区域,叫做 Humongous 内存区域,如图中的 H 块,这种内存区域主要用于存储大对象,即大小超过一个 region 大小 50% 的对象。

G1 的 GC 策略(都会使用)
1️⃣ Minor GC
  • 作用:只回收 新生代(Eden + Survivor)
  • 触发条件:Eden 空间不足
  • 特点:STW,停顿时间短,采用复制算法
  • 老年代:不会回收
  • 频率:最常见
2️⃣ Mixed GC
  • 作用:回收 新生代 + 选定老年代 Region
  • 触发条件:并发标记(Concurrent Mark)完成后
  • 特点:STW 停顿 + 并发辅助,停顿可控
  • 老年代:只回收垃圾最多的 Region
  • 频率:比 Minor GC 少,但比 Full GC
3️⃣ Full GC(兜底)
  • 作用:回收 整个堆(young + old)
  • 触发条件
    • Mixed GC 无法腾出足够空间
    • 出现 Humongous Objects
    • 并发标记失败
  • 特点:单线程标记-整理,停顿时间长
  • 频率:最少 → 尽量避免
年轻代垃圾收集

G1 垃圾收集器中,年轻代的垃圾回收过程使用 "复制" 算法。把 Eden 区和 Survivor 区的对象复制到新的 Survivor 区域。

老年代垃圾收集

对于老年代上的垃圾收集,G1 垃圾收集器也分为四个阶段:

  1. 初始标记 Initial Mark(STW)
    1. 短暂停顿阶段(Stop-The-World),标记从 GC Roots 可直接访问的对象,主要是 young Region 的根对象和老年代直接引用的对象。
    2. CMS 类似,G1 将其与 Minor GC 相结合,在触发 Mixed GC 或并发标记前同时完成初始标记,无需单独 STW。
  2. 并发标记 Concurrent Mark(并发)
    1. 并发标记整个堆的可达对象,同时统计每个 Region 的存活率,为 Mixed GCCleanup 阶段选择垃圾最多的 Region 做准备。
    2. "Garbage First" 名字来源于 G1 优先回收垃圾最多的 Region,以最小化停顿时间。
  3. 最终标记 Remark(STW)
    1. 修正并发标记期间的对象引用变动,使用 SATB(Snapshot-At-The-Beginning)技术提高效率,保证新增可达对象不会被误回收。
  4. 筛选回收 Cleanup(STW)
    1. 回收垃圾最多的 Region,释放空间,准备下一轮 Mixed GC
    2. STW 执行,但只针对被选中的 Region,而不是整个老年代。

G1 是一款面向服务端应用的垃圾收集器。HotSpot 开发团队赋予它的使命是未来可以替换掉 JDK1.5 中发布的 CMS 收集器。如果追求低停顿,G1 可以作为选择;如果追求吞吐量,G1 并不带来特别明显的好处。

G1 vs CMS 对比

特性

G1

CMS

老年代回收

Mixed GC

并发标记-清除

Full GC

避免

容易触发

STW 时间

可控

不可控

内存碎片

标记-整理

可能有碎片 → 需要 Full GC

适用场景

长时间运行,响应要求可控

老、旧服务端应用

四、一个对象的一生⭐⭐⭐

我是一个普通的 Java 对象,我出生在 Eden 区,在 Eden 区我还看到和我长的很像的小兄弟,我们在 Eden 区中玩了挺长时间。有一天 Eden 区中的人实在是太多了,我就被迫去了 Survivor 区的 From 区(S0区),自从去了 Survivor 区,我就开始漂了,有时候在 SurvivorFrom 区,有时候在 SurvivorTo 区(S1区),居无定所。

直到我 18 岁的时候,爸爸说我成人了,该去社会上闯闯了。于是我就去了年老代那边,年老代里,人很多,并且年龄都挺大的,我在这里也认识了很多人。在老年代里,我生活了很多年(每次 GC 加一岁)然后被回收了。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 垃圾回收 GC
    • 一、哪些对象应该被回收❓❓❓
      • ① 引用计数算法(已被淘汰)
      • ② 可达性分析法(Reachability Analysis)⭐⭐⭐
    • 二、垃圾回收算法
      • ① 标记-清除算法
      • ② 复制算法
      • ③ 标记-整理算法
      • ④ 分代算法
    • 三、垃圾回收器
      • ① Serial(新生代收集器,串行GC)
      • ② ParNew(新生代收集器,并行GC)
      • ③ Parallel Scavenge(新生代收集器,并行GC)
      • ④ Serial Old(老年代收集器,串行GC)
      • ⑤ Parallel Old(老年代收集器,并行GC)
      • ⑥ CMS(老年代收集器,并发GC)⭐⭐⭐
      • ⑦ G1(唯一的全区域垃圾收集器)⭐⭐⭐
    • 四、一个对象的一生⭐⭐⭐
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档