您的位置:首页 > 其它

《JVM 系列》- GC三大基础算法

2017-12-23 00:00 218 查看

前言

本文主要计算GC里面的三种基本算法。哪些对象可以被回收,怎么找到这些对象

一、引用计数法

算法原理

引用计数(Reference Count)方式是GC算法中最简单也最容易实现的一种。

它的基本原理是,在每个对象中保存该对象的引用计数,当引用发生增减时对计数进行更新。

引用计数的增减,一般发生在变量赋值、对象内容更新、函数结束(局部变量不再被引用)等时间点。

执行过程分析



箭头指向被依赖的一方。一个对象被几个箭头指向,就表示被引用几次。

如果某个对象(D)的引用失效,这个对象引用的对象(C、E)保存的引用次数就会减少。

当一个对象的引用计数变为0时,则说明它将来不会再被引用,因此可以释放相应的内存空间。

优缺点

优点

其他的GC机制中,要预测一个对象何时会被释放是很困难的,而在引用计数方式是当对象不再被引用的瞬间就会被释放。

由于释放操作是针对每个对象个别执行的,因此和其他算法相比,由GC而产生的中断时间(Pause time)就比较短

缺点

引用计数最大的缺点,就是无法释放循环引用的对象。(对象之间相互引用,但没有被其他对象引用)

在引用发生增减时对引用计数做出正确的增减,而如果漏掉了某个增减的话,就会引发很难找到原因的内存错误。

如果多个线程同时对引用计数进行增减的话,引用计数的值就可能会产生不一致的问题(结果则会导致内存错误)。引用计数管理并不适合并行处理

引用计数方式的语言主要有Perl和Python,为了避免循环引用的问题,都配合使用了其他的GC机制。

二、标记清除算法

算法原理

标记清除(Mark and Sweep)首先从根开始将可能被引用的对象用递归的方式进行标记,然后将没有标记到的对象作为垃圾进行回收。

标记清除算法的处理时间,是和存活对象数与对象总数的总和相关的。

作为标记清除的变形,还有一种叫做标记压缩(Mark and Compact)的算法,它不是将被标记的对象清除,而是将它们不断压缩。

执行过程分析



标记过程:从根开始对可能被引用的对象打上“标记”,这种标记是通过对象内部的标志(Flag)来实现的。重复上述操作,直至所有被引用的对象打上标记。

清除阶段:将全部对象按顺序扫描一遍,将没有被标记的对象进行回收。在扫描的同时,将存活对象的标记清除,一遍下一次GC操作做准备。

优缺点

优点

可以解决计数算法中的循环引用问题。

适合生命周期长的对象

缺点

标记清除算法有一个缺点,就是在分配了大量对象,并且其中只有一小部分存活的情况下,所消耗的时间会大大超过必要的值,这是因为在清除阶段还需要对大量死亡对象进行扫描。

三、复制收集算法

算法原理

复制收集(Copy and Collection)的原理:从根开始将被引用的对象复制到另外的空间中,然后,再将复制的对象所能够引用的对象用递归的方式不断复制下去。

执行过程分析



在就对象之外的“旧空间”,在分配一块“新空间”,并将可能从根被引用的对象复制到“新空间”。

复制完成之后,直接将旧空间释放,而没必要再次扫描每个对象。

下次GC的时候,现在的新空间就成了将来的旧空间。

优缺点

优点

相比标记清楚算法,它只扫描了一次内存空间。

它具有局部性(Lo-cality)。在复制收集过程中,会按照对象被引用的顺序将对象复制到新空间中。于是,关系较近的对象被放在距离较近的内存空间中的可能性会提高,这被称为局部性。局部性高的情况下,内存缓存会更容易有效运作,程序的运行性能也能够得到提高。

缺点

将对象复制一份所需要的开销则比较大,因此在“存活”对象比例较高的情况下,反而会比较不利。

适合生命周期短的对象

参考资料

https://segmentfault.com/a/1190000004665100
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  JVM