JVM 中的垃圾回收算法
前言
在《# JVM 运行时堆内存如何分代?》中介绍了堆内存的分代划分以及垃圾回收的分代收集理论,里面介绍了分代是为了以不同的频率、使用不同的回收算法,进行垃圾回收,以达到效率和内存使用率的平衡。
这篇来介绍一下常见的垃圾回收算法。
「标记-清除」算法
简而言之,分为「标记」和「清除」两个阶段。首先,通过扫描标记出所有需要回收的对象,标记完成后,统一回收掉被标记的对象。也可以反过来,标记出存活的对象,然后回收未被标记的对象。
这个算法有两个缺点:
- 当堆中的对象数量较大,而且大部分都需要被回收时,就需要大量的标记和清除工作,导致这两个过程的执行效率随着对象数量的增长而降低。
- 每次标记和清除之后,会产生大量不连续的内存碎片,导致后续需要分配内存给较大对象时,难以找到足够的连续内存,这个时候就会提前触发新一轮的垃圾回收。
「标记-复制」算法
将可用的内存按容量划分为大小相等的两块,每次只使用其中一块。当使用中的一块内存用完了,就将其中需要继续存活的对象复制到另一块上,然后将以使用的内存空间全部清理掉。
对于大部分对象都需要回收的情况,这个算法只需要复制少数需要继续存活的对象即可,并且同时也解决了「标记-清除」算法存在的内存空间碎片问题。简单、高效。
它的缺点也显而易见:
- 可用的内存空间缩小为原来的一半,空间浪费较多。
- 如果内存中多数对象都是存活的,将产生大量的内存件复制开销。
实际上,「标记-清除」算法是大部分商用 JVM 采用的新生代回收算法。在 JVM 中,新生代的内存空间被分为三个区域:
一个 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 之后依然存活(这个次数可以理解为对象的「年龄」),当这个次数达到一定值之后,那么响应的对象会被晋升至老年代。
「标记-整理」算法
主要针对老年代对象的存亡特征。标记阶段与「标记-清除」算法相同,但是在标记完之后,不是将垃圾对象回收,而是让所有存活的对象都像内存空间的一端移动,然后再直接清理边界以外的内存空间。它是一种移动式的回收算法。
对于老年代的垃圾回收,它不像「标记-清除」算法一样会产生内存碎片,但是,对于老年代这种每次回收都有大量对象存活的区域,移动存活对象并更新引用是一个耗时的操作,并且这个过程中需要暂停用户程序。
比较折中的做法是,大多数时候,采用「标记-清除」算法,暂时容忍碎片的存在,当碎片程度影响到大对象的内存分配至,在用「标记-整理」算法收集一次,起到碎片内存整理的作用。
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanfbafk
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
怎样阻止微信小程序自动打开
PHP中文网 06-13 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
photoshop蒙版画笔没反应怎么办
PHP中文网 06-24