`
janeky
  • 浏览: 364031 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

jvm学习笔记(4)垃圾回收算法分析

    博客分类:
  • jvm
 
阅读更多

  • 简述:
  • 垃圾回收算法有很多种,每种有各自的适用场合,各有千秋,如何在不同的场合搭配使用是我们要考虑的问题

  • 引用计数
  • 这是最简单最原始的算法。原理很简单,对象生成后,有一个相关联的计数器,当有一个地方引用时,计数器加1;当引用失效时,计数器减1。jvm定期扫描对象时,发现计数器为0的对象就可以清除。这个算法的特点是实现简单,速度快。不足之处在于:每次分配和指针操作都需要额外的操作来更新相关计数器。最大的问题是,循环引用的对象是永远没有办法被清除(avm就是这个算法,曾经是as3的码农深有体会)

  • 根搜索算法
  • 这里的根是一些特定的对象:虚拟机栈中引用的对象;方法区的类静态属性引用的对象;方法区中的常量引用的对象;本地方法栈中本地方法引用的对象。每次jvm扫描的时候,从这个根对象开始,有被引用的对象会被加入一条类似“引用链”。这里有点类似深度搜索算法。最后我们可以得出一张类似树形的引用链图。不在这个图的对象就可以清除了。这个算法的不足之处在于扫描时间可能比较长,尤其是引用关系比较复杂时

  • 标记-清除(Mark-Sweep)
  • 顾名思义,包括两个过程。在标记过程,就是采用上面描述的根搜索算法,如果被搜索到,可以在对象本身标记,或者额外记录那些数据被标记。清除的过程比较简单,jvm扫描所有对象,没有被标记的对象就被清除。可以用餐巾纸收集(来源见参考资料,下同)来描述。餐厅里,清洁工要清洁餐巾纸时,先暂停所有人,问每个人,用过那种餐巾纸,在该餐巾纸上做标记。然后清洁工就可以把那些没有被标记的餐巾纸回收了。这个算法有一些不足:效率不高;内存碎片问题。但是这个算法是最经典的垃圾回收算法,后来的很多算法都是在它的基础上改进的

  • 复制算法
  • 复制算法解决了标记-清除算法的效率问题。它的原理是,将内存区一分为二,每次只用其中一块,用完了,就将存活的对象直接拷贝到另外一块区域。这个过程只是移动堆顶指针,不产生内存碎片。很明显,最大的缺点是可以内存少了一半啊。再套用餐巾纸的例子:餐厅里面有两个大厅,大伙现在一个大厅吃饭,到了收垃圾时间了。清洁工让大伙带着正在用的餐巾到另外一个厅。接下来清洁工就可以安心清理无人使用的餐巾纸了。为了解决内存浪费的问题,HotSpot等采用了一个大区间Eden 和两个小区间Survivor From、To。每次回收时,将Eden和其中一个Survivor还存活的对象copy到另外一个Survivor,之后再清理剩下的不再引用的对象。Eden和Survivor的比率通常是8:1,所以只浪费了10%的空间

  • 标记-整理(Mark-Compact)
  • 这个算法是将标记-整理和复制算法的完美结合。同样分两个阶段,标记阶段跟标记-整理算法的标记过程一样。接下来是对复制算法的改进了。不用分成两个区了,而是将被标记的对象向一边移动,未被标记的对象向另外一端移动。最后再收集那些未被标记的对象。再用餐巾纸的例子来说明:第一步同样是对餐巾纸进行标记,接下来清洁工大妈命令所以的就餐者带上被标记的餐巾纸滚到一个角落,顺便把那些没有标记的餐巾纸扔到另外一个角落。大妈就轻松跑到那个角落,轻松搞定那些未被标记的餐巾纸。

  • 增量收集
  • 上面描述的算法都需要暂停程序的执行。增量收集是将传统的垃圾收集算法多进程(或线程)化。这里的难点是:标记过程结束后,执行程序可以又使对象“复活”。

  • 分代收集
  • 这个算法其实是基于数理统计的。不同的对象使用情况可能不同,有些瞬间消逝,有些恒久保留。为此,我们可以建立不同的区间,当对象经过n次考验,依然存活,就将它移到另外一个区域。现代的jvm就是采用了这个思想,分为新生代,持久代。每个区域可以根据情况,采用不用的垃圾收集算法。

  • 参考资料
  • 1.深入java虚拟机
    2.深入理解java虚拟机
    3.通俗解释垃圾回收算法 http://www.game798.com/html/2007-04/3425.htm

    更多关于jvm的内容可以访问 www.iamcoding.com

    0
    1
    分享到:
    评论

    相关推荐

    Global site tag (gtag.js) - Google Analytics