• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

JVM 中的垃圾回收算法

武飞扬头像
juejin
帮助67

前言

在《# JVM 运行时堆内存如何分代?》中介绍了堆内存的分代划分以及垃圾回收的分代收集理论,里面介绍了分代是为了以不同的频率、使用不同的回收算法,进行垃圾回收,以达到效率和内存使用率的平衡。

这篇来介绍一下常见的垃圾回收算法。

「标记-清除」算法

简而言之,分为「标记」和「清除」两个阶段。首先,通过扫描标记出所有需要回收的对象,标记完成后,统一回收掉被标记的对象。也可以反过来,标记出存活的对象,然后回收未被标记的对象。

这个算法有两个缺点:

  1. 当堆中的对象数量较大,而且大部分都需要被回收时,就需要大量的标记和清除工作,导致这两个过程的执行效率随着对象数量的增长而降低。
  2. 每次标记和清除之后,会产生大量不连续的内存碎片,导致后续需要分配内存给较大对象时,难以找到足够的连续内存,这个时候就会提前触发新一轮的垃圾回收。

掘金文章封面.001.jpeg

掘金文章封面.002.jpeg

「标记-复制」算法

将可用的内存按容量划分为大小相等的两块,每次只使用其中一块。当使用中的一块内存用完了,就将其中需要继续存活的对象复制到另一块上,然后将以使用的内存空间全部清理掉。

对于大部分对象都需要回收的情况,这个算法只需要复制少数需要继续存活的对象即可,并且同时也解决了「标记-清除」算法存在的内存空间碎片问题。简单、高效。

它的缺点也显而易见:

  1. 可用的内存空间缩小为原来的一半,空间浪费较多。
  2. 如果内存中多数对象都是存活的,将产生大量的内存件复制开销。

掘金文章封面.001.jpeg

掘金文章封面.002.jpeg

实际上,「标记-清除」算法是大部分商用 JVM 采用的新生代回收算法。在 JVM 中,新生代的内存空间被分为三个区域:

掘金文章封面.001.jpeg

一个 Eden 区域,两个 Survivors 区域。

当一个新的对象被创建的时候,会在 Eden 区域中划出一块作为存储对象的内存。当 Eden 区域空间耗尽的时候,虚拟机会触发一次 Minor GC,来收集新生代的垃圾对象。存活下来的,会被复制到 Survivor 区域。

Servivor 区域被分成了两块(可以看做「标记-复制」算法划分的两块内存区域),分别用 from 和 to 表示。其中 to 区域是空的。每当发证 Minor GC 的时候,Eden 区域和 from Servivor 区域中存活的对象,会被复制到 to Survivor 区域。然后 from 和 to 互换指针(也就是原来的 from 区域作为新的 to 区域),这样,下次进行 Minor GC 时,to 区域还是空的。

这就是新生代运用「标记-复制」算法完成垃圾回收的过程。在这个过程中,虚拟机会记录 Survivor 区域中对象被来回复制了几次,也就是对象在多少次 Minor GC 之后依然存活(这个次数可以理解为对象的「年龄」),当这个次数达到一定值之后,那么响应的对象会被晋升至老年代。

「标记-整理」算法

主要针对老年代对象的存亡特征。标记阶段与「标记-清除」算法相同,但是在标记完之后,不是将垃圾对象回收,而是让所有存活的对象都像内存空间的一端移动,然后再直接清理边界以外的内存空间。它是一种移动式的回收算法。

掘金文章封面.001.jpeg

掘金文章封面.002.jpeg

对于老年代的垃圾回收,它不像「标记-清除」算法一样会产生内存碎片,但是,对于老年代这种每次回收都有大量对象存活的区域,移动存活对象并更新引用是一个耗时的操作,并且这个过程中需要暂停用户程序。

比较折中的做法是,大多数时候,采用「标记-清除」算法,暂时容忍碎片的存在,当碎片程度影响到大对象的内存分配至,在用「标记-整理」算法收集一次,起到碎片内存整理的作用。

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanfbafk
系列文章
更多 icon
同类精品
更多 icon
继续加载