## 精简的垃圾回收 ### 初版 ``` 概念:本地函数:在Ks程序中使用`let`或`mod.`定义的本地函数。 Ks所有的变量都和作用域绑定,因此垃圾回收行为就是回收作用域行为。而能引用作用域内容的只有本地函数,因此问题又演变成了对本地函数的追踪。 每个作用域拥有一个引用计数,声明函数时函数会被Ks绑定在作用域上。当你定义函数,或使用`mod.`导出函数, `let`将函数赋给其他作用域或直接把函数作为参数传走等行为,函数指针明显会被复制的时候,就会沿着其定义处的作用域往上,给每个上层作用域加一层引用计数。 本地函数也属于变量,当本地函数离开当前作用域时,只要它不是当前作用域定义的,就会沿着它原来定义的作用域向上,给每个作用域引用计数减少一层,并将引用计数为0的作用域回收。 ``` ### 作用域的生命周期 Ks中一个作用域要被回收需要两个条件: 1. 作用域内容执行完毕或已返回 2. 作用域的引用计数为0 作用域就是块和函数(即使只有一句也会隐式创建一个块)的上下文。当块创建时会为自己和所有上层作用域增加一层引用计数,当块遇到返回或执行结束时减少一层;如果自己的引用计数是0就会回收自己。 当在作用域内声明函数或在另一处得到函数引用(见下文)时,会为其作用域和所有上层作用域增加一层引用计数。在函数引用所在的作用域结束时,会为其对应的声明处的作用域和上层作用域减少引用计数,并为引用计数为0的作用域和其上层引用计数为0的作用域进行回收。 也就是说块的创建加一层是为了防止回收函数时错误的把上层作用域提前回收。 ``` { let a = 29 { let c(); // 此处回收了c,如果块没有增加一次引用计数就会回收上层作用域,导致下方的a错误访问 } a // Corruption } ``` ### 另一处得到函数引用 所有定义和赋值的行为才需要考虑todrop 1. 作为另一函数的参数 2. 返回 3. 赋值 4. 传入list, struct, object 5. 有函数的list struct object的复制 值得注意的是,以上行为都会引起复制行为,但不代表所有复制行为都会使函数离开作用域,比如假设一个返回函数的函数为f,那么(f())()过程中就会复制f内产生的函数,但并不存在函数离开作用域的可能。 ## ? 能让本地函数比定义此函数生命周期更久的行为只有对作用域外的变量赋值。 ## 复制行为 赋值皆复制。 将变量传进函数作为参数时也有隐式的赋值,也就是说函数得到的参数都是复制而来的。 返回值也必定被复制,因此如果函数只是处理字符,可以使用transfer或Ref声明。 ## api 程序并不保证你的指针是否正确。 let a = 0u; let p:Uint = Mem::ptr(a); // ptr to a let p:Uint = Mem::alloc(20); // ptr to allocator let p = 0; p = 0; ``` Mem::sizeof(Uint); // You cannot bring Types into any other funcs! let a:Uint = Mem::read(p); // type is nessasery Mem::write(p, n); Mem::leak(p); Mem::drop(p); Mem::typeof(a); Mem::alloc(20); ``` ## transmutation ``` let a = 0u; let p = Mem::ptr(a); let f:0i = Mem::read(a); ``` why not `a.into_int()`?