通过与 Jira 对比,让您更全面了解 PingCode

  • 首页
  • 需求与产品管理
  • 项目管理
  • 测试与缺陷管理
  • 知识管理
  • 效能度量
        • 更多产品

          客户为中心的产品管理工具

          专业的软件研发项目管理工具

          简单易用的团队知识库管理

          可量化的研发效能度量工具

          测试用例维护与计划执行

          以团队为中心的协作沟通

          研发工作流自动化工具

          账号认证与安全管理工具

          Why PingCode
          为什么选择 PingCode ?

          6000+企业信赖之选,为研发团队降本增效

        • 行业解决方案
          先进制造(即将上线)
        • 解决方案1
        • 解决方案2
  • Jira替代方案

25人以下免费

目录

GC 算法,永久代对象如何 GC , GC 有环怎么处理

GC 算法,永久代对象如何 GC , GC 有环怎么处理

GC算法是垃圾收集(Garbage Collection)技术中核心的算法,用于自动管理和释放不再使用的内存资源。垃圾收集器通过识别内存中的无用对象、回收内存,使得程序能继续分配新的对象, GC算法确保了应用程序的健康运行。具体到Java虚拟机(JVM)中,永久代(Permanent Generation,简称PermGen)是JVM的内存区域之一,用于存放类信息、常量、静态变量等。从Java 8开始,永久代已被Metaspace(元空间)替代。但不论是永久代还是元空间,GC会在必要时刻对这些区域进行回收。一般情况下,当类被卸载或者相应的ClassLoader实例被回收时,永久代中与之相关的对象就会成为垃圾对象,进而被GC回收

在GC过程中,如果存在对象间的循环引用,现代GC算法(例如标记-清除、标记-整理或者分代收集算法)通过跟踪活跃对象而非非活跃对象来避免回收错误,即使在有环的情况下也能准确地收集垃圾。即使对象间相互引用形成环状结构,只要从根节点(GC Roots)出发无法到达这些对象,这些对象也会被标记为垃圾并且回收

一、GC算法的类型及原理

标记-清除算法

标记-清除(Mark-Sweep)算法是最基础的GC算法。它分为两个阶段:标记阶段和清除阶段。在标记阶段,GC从根集合开始遍历并标记所有可达对象。在清除阶段,清除所有未被标记的对象并释放相应的内存。该算法的缺点是标记和清除过程效率不高,并且清除后会产生大量内存碎片

接下来的段落会讨论其他GC算法,包括标记-压缩、分代收集、增量收集等,以及详细阐述永久代(PermGen)和元空间(Metaspace)中对象的垃圾回收过程。

二、对象的存活判定机制

引用计数法

在引用计数法中,给对象添加一个引用计数器,每当有一个地方引用它时,计数器就加一;当引用失效时,计数器就减一。引用计数为零的对象即被视为可以回收的垃圾。这种方法的主要问题是无法解决对象之间相互引用形成环的问题。

可达性分析法

可达性分析(Reachability Analysis)是目前主流的JVM使用的方法,它通过一系列称为GC Roots的对象作为起点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference ChAIn),当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。这种方法可以有效解决循环引用的问题。

三、分代收集算法

分代假设

分代收集(Generational Collection)算法基于两个经验性的假设:大部分新生对象很快无用、不再使用的对象和长时间存活的对象差异较大。因此,将对象分代,并根据不同代的特点采取相应的收集算法。一般而言,新生代使用复制算法,老年代使用标记-清除或标记-整理算法。

新生代与老年代

JVM的堆内存被分为新生代(Young Generation)和老年代(Old Generation),其中新生代进一步划分为一个Eden区和两个Survivor区(通常称为From和To)。新生代对象大量产生且死亡快速,老年代则存放长期生存的对象

四、垃圾回收器的实现

Serial GC

Serial GC适用于单线程环境,它为新生代使用标记-复制(Mark-Copy)算法,为老年代使用标记-清除-压缩(Mark-Sweep-Compact)算法。它的特点是简单高效,对于内存资源受限且单核处理器的应用来说,是一个不错的选择

Parallel GC & CMS GC & G1 GC & ZGC & Shenandoah

这些都是高级的垃圾回收器,Parallel GC采用多线程对新生代进行垃圾回收,CMS(Concurrent Markup Sweep)旨在减少应用暂停时间,G1(Garbage-First)适用于大内存的机器,而ZGC(Z Garbage Collector)与Shenandoah则为最新的低暂停时间的垃圾收集器

五、永久代与元空间中的垃圾回收

永久代(PermGen)的GC

JVM的永久代是存放类信息和方法信息的地方,随着类的加载和卸载,永久代也会发生变化。当类不再被需要时,对应的空间可以被回收。JVM在执行Full GC时会回收永久代空间。但是,随着Java 8的发布,永久代已被逐步淘汰。

元空间(Metaspace)的GC

替代永久代的元空间,用本地内存(Native Memory)存放类信息,与永久代不同,它不在虚拟机内存中而是使用本地内存。因此,其大小受本地内存限制。元空间并不受到Java堆大小的限制,其回收主要涉及卸载类和类加载器。只有在发生Full GC时,Metaspace才会被垃圾回收器清理。

相关问答FAQs:

1. 什么是GC算法,它是如何工作的?

GC算法是垃圾回收算法的简称,它用于自动回收不再使用的内存空间,以避免内存泄漏和系统崩溃。GC算法工作原理是通过检测和标记内存中的活动对象,然后释放那些未被标记的不再使用的对象。常见的GC算法有标记-清除法、复制算法、标记-整理法等。

2. 永久代对象如何进行GC?

永久代是Java虚拟机中用于存储类、方法、常量等的内存区域。在旧版Java虚拟机中,永久代中的对象是不会被GC回收的。然而,随着Java 8的发布,永久代被元空间(Metaspace)取代,永久代中的对象也会被垃圾回收。元空间使用的是本地内存而不是虚拟机堆内存,所以不再面临永久代溢出的问题,GC算法会自动回收不再使用的永久代对象。

3. GC有环怎么处理?

当对象之间形成环状引用时,即互相引用,但又没有被任何外部对象引用时,这就是GC有环的情况。这种情况下,传统的引用计数法无法正确地回收这些对象,因为它们的引用计数不为0。

为了解决这个问题,现代的垃圾回收算法使用了根可达性算法(Root Reachability Algorithm),它通过从程序的根对象开始遍历,找到所有从根对象可达的对象,并将其标记为活动对象。对于没有被标记的对象,则被视为不再使用的垃圾对象,将其回收。通过这种方式,GC可以正确地处理有环的情况,避免内存泄漏。

相关文章