前言
今天狂风大作,雨滴慢慢的滴了下来。天气很冷,我也就不在公司耗着了。回家再为大家分享今天的学习内容吧。
其实,真的,作Java与Go的学习对比,其实还是比较费劲。想全所有的点,也比较累。哈哈,今天还是继续偷懒下,等着时间比较多,再好好梳理,继续差异的对比。
今天,群里小伙伴有说,Go的垃圾回收。那么,我简单说一下golong历史上跨越比较大的垃圾回收算法,三色标记算法。
垃圾回收
我们在学习java时,就被垃圾回收深深的折磨着。jdk8之后,垃圾回收器包含线性、并发标记清除和G1四个垃圾回收器。想要了解他们的工作原理和实现细节,需要花费很多的时间和精力。很多人,可能工作多年,也无从下手,也没有好好理解Java是如何执行垃圾回收的。
Go语言的垃圾收集从诞生的第一天就一直不断演进,从1.0开始,基本上没个版本,都在更新着性能。
其中比较重要的一个节点,是1.5版本。实现了基于三色标记清扫的并发垃圾收集器;
- 大幅度降低垃圾收集的延迟从几百 ms 降低至 10ms 以下;
- 计算垃圾收集启动的合适时间并通过并发加速垃圾收集的过程;
很多人,不是很了解三色标记算法。今天,我们来简单了解下,它是如何发挥魅力的。
三色标记清除算法
为什么需要三色标记
在三色标记法之前有一个算法叫 Mark-And-Sweep(标记清扫),这个算法就是严格按照追踪式算法的思路来实现的。这个算法会设置一个标志位来记录对象是否被使用。最开始所有的标记位都是 0,如果发现对象是可达的就会置为 1,一步步下去就会呈现一个类似树状的结果。等标记的步骤完成后,会将未被标记的对象统一清理,再次把所有的标记位设置成 0 方便下次清理。
这个算法最大的问题是 GC 执行期间需要把整个程序完全暂停,不能异步进行 GC 操作。因为在不同阶段标记清扫法的标志位 0 和 1 有不同的含义,那么新增的对象无论标记为什么都有可能意外删除这个对象。对实时性要求高的系统来说,这种需要长时间挂起的标记清扫法是不可接受的。所以就需要一个算法来解决 GC 运行时程序长时间挂起的问题,那就三色标记法。
三色标记优势
相比传统的标记清扫算法,三色标记最大的好处是可以异步执行,从而可以以中断时间极少的代价或者完全没有中断来进行整个 GC。
三色标记法很简单。首先将对象用三种颜色表示,分别是白色、灰色和黑色。最开始所有对象都是白色的,然后把其中全局变量和函数栈里的对象置为灰色。第二步把灰色的对象全部置为黑色,然后把原先灰色对象指向的变量都置为灰色,以此类推。等发现没有对象可以被置为灰色时,所有的白色变量就一定是需要被清理的垃圾了。
三色标记法(来自维基百科)
三色标记法因为多了一个白色的状态来存放不确定的对象,所以可以异步地执行。当然异步执行的代价是可能会造成一些遗漏,因为那些早先被标记为黑色的对象可能目前已经是不可达的了。所以三色标记法是一个 false negative(假阴性)的算法。
除了异步标记的优点,三色标记法掌握了更多当前内存的信息,因此可以更加精确地按需调度,而不用像标记清扫法那样只能定时执行。
总结
三色标记法其实很容易理解,但是这个思想解决了很大的问题。