# Ks垃圾回收 我使用了一种我自称Outlive的算法来回收垃圾,本质上是引用计数的改造。 Ks的变量都绑定在作用域上,而且"赋值皆复制"设计的存在隐去了Ks中引用的存在。因此变量的回收就是作用域的回收,而作用域的回收条件存在两个: 1. 作用域结束 2. 作用域内部定义的函数没有被作用域外拿到 让作用域外得到作用域内定义的函数称为Outlive(生命周期延长)。以下是最简单的例子(伪代码,无法运行)。 ``` 'a{ let out 'b{ let b(); out = b; } } ``` 我们将上述作用域称为'a和'b,在`out = a`的过程中,Ks发现你让'b外的作用域拿到了b函数,则本来应该在'b结束时释放的b函数就不能释放了,'b和它的所有上级作用域都会增加一层Outlive引用计数(Reference Count for Outliving),并为持有b函数的目标作用域(out处于'a作用域)中添加一个函数标记,叫作to_drop(将被释放),告诉它在结束时要减少一层该函数的引用计数。 以下是`out = b`后作用域的状态 ``` 'a(count:1,to_drop:[b]) { let out 'b(count:1,to_drop:None){ let b(); >>> out = b; } } ``` 再往下一行,'b作用域执行完了,但因为自己的count是1,就暂时不回收。继续往下,'a作用域结束了,如下 ``` 'a(count:1,to_drop:[b]) { let out 'b(count:1,to_drop:None){ let b(); out = b; } >>>} ``` 暂时不回收,那什么时候回收?看现在的状态:'a结束时发现to_drop里是有函数引用的,就把所有函数引用对应的原来的作用域的引用计数,从里往外减一层,并将此时发现引用计数为0的作用域给回收掉。 简单说就是,'a结束时找到to_drop中的b函数,它的作用域是'b,于是先从'b开始从里往外减一层引用计数,但这个过程中发现'b引用计数被减为0了就顺便回收掉'b,往上'a减一也成0了就顺便回收'a。 这就是Outlive垃圾回收的基本思想,实际行为中为了防止to_drop的函数回收时提前回收未执行完的作用域,还为作用域设置了ended标签,只有运行结束了的作用域才能被to_drop的函数回收给带走。 ## Static Outliving 有一些行为会让函数在整个程序期间都不会释放,我称之为Outlive to Static(无限HP)。 1. 模块导出 2. 传入Native函数的参数