注意:本文重点在实现(x86 gcc unix like环境下),不在算法(否则也不用最简单的回收算法),并且纯属教学 (娱乐) 作用,不讲究效率,但求能用即可,也没有继续做到支持多线程。
具体代码放在github上:[https://github.com/Yuandong-Chen/singlethreadGC]
目录:
实现中的重难点介绍:
对外接口部分示意代码:
#include "interface3.h"
#include <...> // 必要头文件
int main()
{
__gc_init(); /* to init gc */
/*add some code you like*/
...
/* need some memory in heap */
void *forgetToFree = (void *)gc_calloc(sizeof(struct XXX));
/*add some code you like*/
...
__gc_exit(); /* to destroy gc */
return 0;
}
如何找到mark&sweep的根节点:
i) 对于自动变量的标记,从当前栈顶一直向上找到environ指正位置即可,当然也可以通过在程序中读入/proc/pid/maps 查看栈底地址。 然后,只要把这些区域标记即可。
ii) 对于全局变量的标记,利用链接器变量 _etext, _end标记即可。( 注意 gcc工具是支持的,但是其他编译链接工具完全不能保证 )
iii) 对于临时变量,标记当前寄存器。
具体代码片段:
marksweep.c 文件中:
static unsigned int stack_bottom = 0;
extern char _end[];
extern char _etext[];
extern char** environ;
void gc_collect()
{
unsigned int stack_top;
unsigned int _eax_,_ebx_,_ecx_,_edx_,_esi_,_edi_;
asm volatile ("movl %%ebp, %0" : "=r" (stack_top));
asm volatile ("movl %%eax, %0" : "=r" (_eax_));
asm volatile ("movl %%ebx, %0" : "=r" (_ebx_));
asm volatile ("movl %%ecx, %0" : "=r" (_ecx_));
asm volatile ("movl %%edx, %0" : "=r" (_edx_));
asm volatile ("movl %%esi, %0" : "=r" (_esi_));
asm volatile ("movl %%edi, %0" : "=r" (_edi_));
/* 我们标记一些寄存器里头的临时变量 */
mark(_eax_);
mark(_ebx_);
mark(_ecx_);
mark(_edx_);
mark(_esi_);
mark(_edi_);
mark_from_region((ptr *)((char *)stack_top + 4),(ptr *)(stack_bottom)); //我们标记自动变量
mark_from_region((ptr *)((char *)_etext + 6),(ptr *)(_end)); //我们标记全局变量
sweep();
}
int __gc_init()
{
unsigned int stack_top;
unsigned int curr;
asm volatile ("movl %%ebp, %0" : "=r" (stack_top));
curr = stack_top;
/* 用简单的循环检查出栈底地址(有逻辑漏洞) */
while(*(unsigned int *)curr != (unsigned