一、 回收算法
GC模块的回收算法只用到了标记清除算法(make-sweep),通过标记的方法将内存分为free和mark状态,每次调用回收函数时会将未mark的区域回收。当内存使用达到阈值或者主动调用GC.collect()会进行垃圾回收。
二、 内存分布
被管理的内存空间分为三部分,分别是alloc table(ATB)、finaliser table(FTB)、和pool(详细算法见gc_init函数)。
分配的最小单位为block,块的大小通过BYTES_PER_BLOCK设置。
alloc table:用来记录每个block的状态,状态分为mark、free、head、tail四种,用两个bit表示状态。
Finalizer table:用来记录block是否使用finaliser(__del__方法),用一个bit表示。
Pool: 用户使用的空间。
三、 标记回收过程
内存可以分为四种标记状态:mark、free、head、tail
Micropython的GC回收主要使用两个函数gc_collect_root、gc_sweep
gc_collect_root主要遍历栈中正在使用的gc内存,并将其mark防止被释放,之后再调用gc_sweep进行回收,将所有未标记的内存 (head和tail),gc_sweep会遍历所有block将未标记的内存进行回收释放(标记为free状态),已经标记的块再次置为未标记状态(),用于下次回收,这样就形成了垃圾回收的循环。
MicroPython中GC模块的源码:
void gc_collect(void) {
//标记虚拟机中的区域,防止内存被踩踏
gc_collect_start();
#if MICROPY_PY_THREAD
// trace root pointers from any threads
//多线程模式标记每个线程的内存
mp_thread_gc_others();
#else
//单线程模式标记当前线程的内存
gc_collect_root(rt_thread_self()->sp, ((mp_uint_t)((void *)MP_STATE_THREAD(stack_top) - rt_thread_self()->sp)) / 4);
#endif
//将未标记的内存进行统一回收
gc_collect_end();
gc_dump_info();
}
四、 Micropython GC模块缺陷
相对于cpython和java等高级语言的垃圾回收机制,缺少分代算法、引用计数算法、复制算法等方式提高稳定性和回收效率。