打扫房间的各种方法 —— Java虚拟机的垃圾收集算法清单

原创 2017年08月20日 16:15:14

带着问题阅读

  • 垃圾收集时,除了效率,还要考虑什么?
  • 如果你是JVM设计者,在标记完可回收的对象后,你会怎么去收集垃圾对象?


导语

通过前面两讲的学习,我们已经知道JVM是如何判断对象是不是可以回收,以及回收是如何发起的。那么发起之后又是如何进行收集的呢,收集的算法有哪些,这是我们这一讲的内容。

本文是Effective Java专栏Java虚拟机专题的第六讲,如果你觉得看完之后对你有所帮助,欢迎订阅本专栏,也欢迎您将本专栏分享给你身边的工程师同学。

在学习本节课程之前,建议您了解一下以下知识点:


标记-清除算法

标记-清除算法是最基础的垃圾收集算法,这个算法在收集垃圾时分两步:

  1. 标记所有需要回收的对象;
  2. 标记完成后统一回收所有被标记的对象。

之所以说它是最基础的收集算法,是因为后续的收集算法都是基于这种思路并对其进行改进而得到的。

它的不足主要有两个:

  • 一是效率问题,这种逐个进行清除的算法,效率固然不高;
  • 另一个是空间问题,标记清除后会产生大量不连续的内存碎片,导致以后需要分配较大对象时,无法找到足够大的连续内存而不得不提前触发一次垃圾收集动作。

注:《深入理解Java虚拟机》中,关于效率问题,周老师的原文是“标记和清除的效率都不高”,这里个人理解,标记是其他算法也需要的,所以标记效率不高不可以作为不选择这个算法的理由。

可以用下面这张图来理解标记-清除算法:



复制算法

针对标记-整理算法的不足,一种称为“复制”的算法出现了,它的收集步骤如下:

  1. 将内存划分为大小相等的两块;
  2. 当其中一块内存用完时,把存活对象复制到另一块上去,然后把原来的那一块全部清理掉。

这种算法实现简单,运行高效,同时也不会有内存碎片,代价是需要将内存缩小为原来的一半。

可以用下面这张图来理解“复制”算法:


现代虚拟机都采用这种算法来回收新生代根据IBM的专门研究,新生代中的对象,98%是“朝生夕死”的,所以没有必要按照1:1来划分成两个一样大小的内存,而是将内存划分为一块大的Eden区和两块小的Survivor区域每次使用Eden和其中一块Survivor

回收时,把Eden和使用的那块Survivor中存活的对象,一次性复制到那块未使用的Survivor中,然后清理掉Eden和刚刚使用的Survivor。

HotSpot虚拟机默认Eden和Survivor的大小比例是8:1,也就是说,每次新生代中可用内存为90%(80% + 10%),只有10%的内存会被浪费。

那么假如一次回收时,超过了10%的对象存活,Survivor内存不够存放时,该怎么办?

这时候就需要老年代来进行分配担保(Handle Promotion).

内存分配担保是指:如果另一块Survivor没有足够空间存放上一次新生代垃圾收集后留下来的存活对象,那么这些对象直接进入老年代。关于分配担保,后续课程还会详细介绍。


标记-整理算法

复制算法在对象存活率较高时就要做很多的复制操作,并且会经常需要分配担保,因此,这种算法是不适用于老年代的。

根据老年代存活率高的特点,有人提出了“标记-整理”算法,算法和“标记-清理”算法类似,但是标记之后,不直接对标记为可回收的对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉边界外的内存

可以用下面这张图来理解标记-整理算法



换个角度理解这几种算法

相信很多人看到这里,对于上面提到的几种算法的优劣,内存碎片那一块还是都可以理解的。比较难理解的是效率的问题,为什么“标记-整理”和“复制”算法就比“标记-清除”效率高呢?

我们可以这样理解,假设我们要清理一个文件夹中的文件:

“标记-清理”算法会这样做:先把要删除的文件,文件名前面加个“toDelete_”,表明是要删除的文件,然后对所有toDelete*的文件,逐个点击-右键-删除;在Linux上就是 rm -rf toDelete_file1.txt rm -rf toDelete_file2.txt rm -rf toDelete_file3.txt;......


“复制”算法也是标记哪些文件要删除,然后把不需要删除的文件,拷贝到另一个文件夹,接着在原来的文件,ctrl+A,右键-删除,一把全部删了。在Linux上就是 rm -rf *:


而“标记-整理”算法,也是先标记,接着把文件列表按照文件名排序,然后按住shift,选中从第一个“toDelete_”的文件,到最后一个文件之间的全部文件,然后右键-删除。在Linux上就是,rm -rf toDelete_*


这样就能理解为什么“标记-清理”会比其他两种算法慢了吧 :)


总结

这一讲讲解了虚拟机进行垃圾收集的几种常用算法,下一讲,我们就要看看,这几种算法,或者说方法论,是如何在各种垃圾收集器中具体实现的,同时我们也将一起了解JVM中,到底有哪些垃圾收集器。


参考资料

版权声明:本文为博主原创文章,未经博主允许不得转载。

Java虚拟机的垃圾收集算法

一 标记-清除算法(Mark-Sweep)   首先标记出所有需要回收的对象,标记完成后统一回收。   主要缺点: 1. 标记和清除效率都很低 2. 产生大量不连续的内存碎片,导致后面分配...
  • u011905238
  • u011905238
  • 2013年09月04日 09:24
  • 411

luogu3877 [TJOI2010]打扫房间

(http://www.elijahqi.win/2017/12/31/luogu3877-tjoi2010%E6%89%93%E6%89%AB%E6%88%BF%E9%97%B4/%20%E2%80...
  • elijahqi
  • elijahqi
  • 2017年12月30日 21:21
  • 19

Hotspot虚拟机- 垃圾收集算法和垃圾收集器

当提到Java虚拟机的时候,我们首先应该区分2件事情。一个是抽象的[Java虚拟机规范](https://docs.oracle.com/javase/specs/jvms/se7/html/),另一...
  • xlinsist
  • xlinsist
  • 2016年10月19日 13:38
  • 694

分Java虚拟机的垃圾收集算法

分Java虚拟机的垃圾收集算法   主要缺点: 1. 标记和清除效率都很低 2. 产生大量不连续的内存碎片,导致后面分配大内存空间失败二 复制算法将可用内存划分为大小相等的两块, 每次只使用其中...
  • u014552589
  • u014552589
  • 2014年04月05日 08:31
  • 310

java虚拟机-垃圾收集算法

1.标记-清除算法 算法分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。主要不足有两个:一个是效率问题,标记和清除两个过程的效率都不高;另一个是空...
  • u010059036
  • u010059036
  • 2016年08月03日 17:42
  • 103

java虚拟机---垃圾收集算法

java虚拟机---垃圾收集算法 1.标记-清除算法 2.复制算法 3.标记-整理算法 4.分代手机算法:...
  • Q176782
  • Q176782
  • 2017年06月05日 12:09
  • 113

Java虚拟机学习----垃圾收集算法

跟踪收集器采用的是集中式的管理方式,全局记录对象直接的引用状态,执行时从一些GC Roots的对象做为起点,从这些节点向下开始进行搜索所有引用链,当一个对象到GC Roots 没有任何引用链时,则证明...
  • Cai_xw1993
  • Cai_xw1993
  • 2016年11月18日 11:31
  • 173

读书笔记-->Java虚拟机垃圾收集算法

前言 熟悉虚拟机的垃圾收集算法有助于我们更好的了解Java内存的分配策略。对我来说,以前也有去了解过虚拟机相关的知识点,但是比较零碎。这次拜读《深入理解Java虚拟机》,真是相当后悔自己为啥不早点去读...
  • chan1116
  • chan1116
  • 2016年02月03日 17:24
  • 317

Java虚拟机 - 垃圾收集算法

目录(?)[+] 跟踪收集器 标记 - 清除算法 复制算法 标记  - 整理算法 引用计数收集器 跟踪收集器 跟踪收集器采用的为集中式的管理方式,全局记录对象之间的引用状态,执行时从一些列G...
  • fdhdjfkjfkjt43486
  • fdhdjfkjfkjt43486
  • 2014年03月15日 23:59
  • 305

Java虚拟机之垃圾收集算法

一、标记-清除算法 算法分为标记和清除两个阶段。 首先标记需要回收的所有对象,然后在标记完成后,统一回收所有被标记的对象。 不足:1.效率问题。标记和清除两个过程的效率都不高             ...
  • weililansehudiefei
  • weililansehudiefei
  • 2017年05月16日 21:44
  • 409
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:打扫房间的各种方法 —— Java虚拟机的垃圾收集算法清单
举报原因:
原因补充:

(最多只允许输入30个字)