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

JVM 垃圾回收算法

我用通俗易懂的方式介绍一下GC算法,包括标记-清除、复制、标记-整理、分代收集

把 Java 堆想象成一个巨大的 “停车场”,里面停满了各种 “车辆”(也就是对象)。有些车是 “正在使用的”(可达对象),有些车是 “废弃的”(垃圾对象)。GC 算法就是不同的 “清障车” 工作模式,它们的目标都是:高效地把废弃的车辆清理掉,腾出空间给新的车辆停放。


算法一:标记 - 清除(Mark-Sweep)

比喻:按名单找车,然后直接拖走。

这是最基础、最直接的一种算法,分为两步:

  1. 标记(Mark):清障队拿着一份 “活跃车辆名单”(从 GC Roots 开始遍历),在停车场里找到所有 “正在使用的车”,并在它们的挡风玻璃上贴一个 “保留” 的标签。
  2. 清除(Sweep):清障队再次遍历整个停车场,把所有没有“保留” 标签的车(废弃车辆)全部拖走。清理完后,他们会记录下这些空出来的 “停车位”(内存碎片),方便以后分配。

优点:

  • 简单直接:实现容易,思路清晰。
  • 不需要移动对象:只做标记和清除,不改变对象的位置。

缺点:

  • 效率不稳定:如果停车场很大,车很多,两次遍历(标记和清除)都会很慢。
  • 产生内存碎片:清理后,空出来的停车位是零散的。当有一辆 “加长林肯”(大对象)要进来时,可能找不到一整块足够大的连续停车位,即使总的空位够,也只能触发一次新的 GC。

算法二:复制(Copying)

比喻:把有用的车挪到新停车场,旧停车场直接废弃。

为了解决标记 - 清除的碎片问题,复制算法应运而生。它把停车场一分为二,通常是 From 区 和 To 区

  1. 复制(Copy):清障队拿着 “活跃车辆名单”,把 From 区里所有 “正在使用的车” 都完好无损地复制到 To 区,并且是紧凑地、连续地停放。
  2. 交换(Swap):复制完成后,From 区里剩下的肯定全是废弃车辆。这时,清障队直接宣布整个 From 区作废,然后把 From 区和 To 区的角色互换。下一次 GC 时,就从新的 From 区复制到新的 To 区。

优点:

  • 效率高:因为只处理 “正在使用的车”,如果大部分都是废弃车辆,复制的工作量就很小。
  • 无内存碎片:新对象总是在一个干净、连续的空间里分配,像新建的停车场一样整齐。

缺点:

  • 空间浪费:永远有一半的停车场是空着的,内存利用率低。
  • 对象移动成本高:如果 “正在使用的车” 很多,复制它们会非常耗时,并且需要更新所有指向这些被移动对象的 “引用”(相当于通知所有车主他们的车位变了)。

算法三:标记 - 整理(Mark-Compact)

比喻:先标记要保留的车,然后把它们都挪到停车场的一端,剩下的一次性清空。

这是为了解决 “标记 - 清除” 的碎片问题和 “复制” 算法的空间浪费问题而设计的,主要用于老年代。

  1. 标记(Mark):和 “标记 - 清除” 算法一样,先给所有 “正在使用的车” 贴上 “保留” 标签。
  2. 整理(Compact):清障队把所有贴了 “保留” 标签的车,像 “拼图” 一样,向停车场的一端移动,让它们紧紧地挨在一起。
  3. 清除(Clear):所有保留的车都移走后,停车场另一端剩下的一大片连续区域就可以一次性全部清空

优点:

  • 无内存碎片:整理后,内存空间是连续的。
  • 内存利用率高:不需要像复制算法那样预留一半空间。

缺点:

  • 效率更低:在标记的基础上,增加了 “移动对象” 的步骤,这个过程非常耗时,尤其是对象很多的时候。

算法四:分代收集(Generational Collection)

比喻:按车辆使用频率,分不同区域管理。

这不是一种具体的算法,而是一种 “分而治之” 的策略 。它基于一个重要的观察:大部分对象都是 “朝生夕灭” 的(新生代),只有少数对象能活很久(老年代)。

于是,停车场被划分为两个区域:

  1. 新生代(Young Generation)

    • 比喻“临时停车区”
    • 特点:车流量大,大部分车停一会儿就走。
    • 算法:采用复制算法。因为新生代中大部分都是垃圾,需要复制的存活对象很少,效率极高。它内部又分为一个 Eden 区和两个 Survivor 区(From 和 To)。
  2. 老年代(Old Generation)

    • 比喻“长期停车区”
    • 特点:车很稳定,进来了就可能停很久。
    • 算法:采用标记 - 清除标记 - 整理算法。因为老年代中大部分对象都是存活的,使用复制算法成本太高。

工作流程:

  • 新车(新对象)先停在新生代的 Eden 区。
  • Eden 区满了,触发一次 Minor GC(新生代 GC)。
    • 把 Eden 和 From Survivor 区里存活的对象,复制到 To Survivor 区。
    • 清空 Eden 和 From Survivor 区。
    • From 和 To 区角色互换。
  • 对象在 Survivor 区之间来回被复制,每复制一次 “年龄” 就加一岁。
  • 当对象年龄达到一个阈值(比如 15 岁),就会被 “晋升” 到老年代
  • 当老年代也快满了,就会触发 Major GC / Full GC(老年代 GC),这个过程通常比较慢。

优点:

  • 极高的整体 GC 效率:针对不同生命周期的对象,使用最合适的算法,扬长避短。新生代 GC 非常快,而老年代 GC 虽然慢,但发生频率低。

总结对比

算法比喻优点缺点适用场景
标记 - 清除按名单拖走废车实现简单,不移动对象效率低,产生碎片老年代(作为兜底或与整理结合)
复制挪走有用的车,废弃旧车场效率高,无碎片空间浪费,移动成本高新生代
标记 - 整理挪车挤到一端,再清另一端无碎片,内存利用率高效率低,移动成本高老年代
分代收集分临时 / 长期停车区管理综合效率最高,应用最广实现复杂所有现代 JVM 的标准策略

一句话总结:现代 JVM 都采用分代收集策略,在新生代复制算法,在老年代标记 - 清除 / 整理算法,这样既能保证 GC 的高效性,又能解决内存碎片问题。

http://www.dtcms.com/a/478672.html

相关文章:

  • 宁波企业如何建网站网站 提示危险
  • 嵌入式开发--STM32H7系列的硬件SPI的读写函数问题
  • printk 使用技巧
  • 深度学习入门(六)——模块、正则化与工程调优全解析
  • python高级05——HTTP协议和静态服务器
  • 现在网站一般做多大的南沙网站建设哪家好
  • 使用Mathematica做Lorenz系统的稳定性分析
  • centos升级redis至最新版(绿色版)
  • 做logo宣传语的网站电影网页设计素材
  • 从C++开始的编程生活(11)——string类基本语法和string类的基本实现
  • 南宁网站建设策划外包培训机构营销方案
  • 建站用什么搭建比较好网站后台是什么
  • 官方网站开发与定制广州网道营销广告有限公司
  • 设置 windows nginx.exe 每天 重启
  • 优先级队列(堆)-703.数据流中的最大值-力扣(LeetCode)
  • 亚马逊自养号测评新手从零起步:环境搭建全流程指南
  • 数据结构_栈和队列
  • 江苏优化网站关键词wordpress子域
  • 怎么用Visio studio做网站北京网页网站设计制作
  • html css网页制作成品——HTML+CSS盐津铺子网页设计(5页)附源码
  • 网站编辑简历网站建设域名什么意思
  • 如何做网站内链优化个人网站建设咨询电话
  • 网站色彩搭配原则拼多多 wordpress
  • 网站建站网站设计公司深圳网站建设 龙华信科
  • 花瓣网是仿国外那个网站做的深圳全网营销方案
  • 网站首页引导页 模版网站制作类软件推荐
  • 【LeetCode】71. 简化路径
  • 基于 go 的分布式缓存
  • 网站建设合同要求黄冈做网站公司
  • 封装的实现和定义