一、主要算法及分类
垃圾回收在前面提到其中重要的一环就是相关算法的实现。算法的优劣和适应性,体现了其应用的广度和深度。垃圾回收的概念提出很早,而最近这些年来,随着一些新兴语言的出现,GC的算法不断推陈出新。在各自的应用范围内大显身手。不过到目前为止,GC算法仍然存在着各种各样的问题,很难在宽范围的领域内适用。
或者这样说,一个算法,要想兼顾所有的问题解决需求,是不可能的,至少现在是不可能的,只能寻求一个尽量公平适用的范围。
GC目前主要的算法主要有以下几类:
1、引用计数器
2、标记处理类
3、增量处理类
4、分代处理类
5、混合类
二、优缺点
各类算法各有优缺点,下面就分析一下(其实应该搞张表,不过太懒,还是写文字):
1、引用计数器
这种方式简单、灵活,缺点就在于它可能会产生循环引用等导致无法释放回收的垃圾内存,结果就是长时间的运行导致内存崩溃。同时,对象太多导致引用计数器增减太频繁,也会产生很多问题,特别是吞吐量的问题。
2、标记处理类
标记处理类这种应用非常多,包括新兴的Golang都是使用这种,搜索类算法也归到这类中。这种算法其实就是通过遍历所有内存对象,标记状态,通过状态来判断是否为使用对象。在到达一个阈值后,停顿整个操作,进行扫描,未使用的对象回收。在这个过程中,对内存中的已有对象进行处理(压缩、移动、合并等等)。它的优点是无需担心内存问题,缺点也很明显,需要不断的遍历内存中的对象,处理也需要时间和内存,对效率上来讲也是一个巨大的开支。
3、复制算法
复制算法就是把内存分成指定的块,一些块使用,一些块备用,使用的块在达到一个阈值后,就拷贝到备用块中。这个算法优点是简单,特别是可以消除碎片化内存;缺点是成本高,效率低。
4、增量处理类
增量处理的这种GC,一般来说目的是为了解决常见的标记类的最大暂停时间出现的,它其实也是一种标记算法,常见的就是三色标记。通过不同的颜色来处理不同状态的内存对象(已搜索、未搜索和正在搜索)。它的优点是减少了最大暂停的时间,但仍然未解决标记类算法的主要问题。
5、分代处理类
分代类算法,本质并没有脱离标记类算法或者说引用计数器算法,应该更明确的说是他对标记或者引用计数器算法的一个优化。通过把内存对象的回收可能性,把内存逻辑划分成老年代、新生代和元数据代,叫法各有不同,但意义基本一致。这样,通过对不同区域的内存对象进行处理,大大减少了遍历等操作的次数,提高了效率。缺点是未必适合所有程序,导致反作用情况出现。也就是不一定年轻代的就要回收,同样,老年代也未必就长久存在。不同代际之间的对象处理也容易产生误处理。
6、混合类
从名字就知道,一般混合类都是为了博采众家之长。可以把引用计数器和其它的一些处理方式组合起来,可以较大幅度增加吞吐量并减小其它副作用。一般来说,混合型的选取种类配合非常重要,而且应用场景也比较受限。
三、基本应用
GC的应用就非常广泛了,比如常见的JAVA、c#、Go、Python,还有早期的Lisp等等。Java的Gc不断的发展,已经发展了三代,从早期的计数器方式到后来标记类复制,再到后期的分代。现在使用的是G1算法。而go使用的标记清除算法,号称是特别厉害。可是在大内存的GC中还是有问题,最大停止时间太长。而Python使用是计数器方式,主要是简单,毕竟Python也没啥超级重量级的应用,这方面还没有提出更高的要求。
四、总结
垃圾回收,其实有点出风头。真正做的好的目前看还是没有。大多数主流的GC都会受限场景,结果就是在不同的场景下要对其进行配置,最典型的就是Java。不过方向是明确的,还需要各位大佬们前仆后继永远向前。接下来会对相关的一些GC的技术展开分析说明,还是要努力学习别人的优点,以为已用。
“师夷人之技以制夷”。