洞察力+实践 :)




对python的垃圾回收机制的较完整描述
http://wiki.woodpecker.org.cn/moin/python_ref_circle_gc

我是个懒人啊,老早就研究过一小点gc,但是一看c语言代码就郁闷了。

今天下午把一直想试试的leo弄下来玩,顺便下下来pythonGC.leo,一会就把整个脉络弄清楚了,leo在阅读复杂代码方面确实不错,其他的好处,挖掘中...,呵呵

如果对一些gc基本不了解,建议先看我以前写的一篇blog,开始了:

// 这个函数最关键,阅读这个函数能够帮助理解收集工作大致是如何进行的

static long
collect(PyGC_Head *young, PyGC_Head *old)
{
/*young是当前收集的一代,还有用的对象放到old这一代*/
long n = 0;
long m = 0;
PyGC_Head reachable;
PyGC_Head unreachable;
PyGC_Head finalizers;
PyGC_Head *gc;

if (debug & DEBUG_STATS) {
PySys_WriteStderr(
"gc: collecting generation %d...\n"
"gc: objects in each generation: %ld %ld %ld\n",
generation,
gc_list_size(&_PyGC_generation0),
gc_list_size(&generation1),
gc_list_size(&generation2));
}

/* 使用 ob_refcnt 和 gc_refs, 计算容器集合中哪些对象
* 从该集合外部可达的 (比如考虑了容器内部所有应用
* 之后,refcount仍然大于0) */
update_refs(young);
subtract_refs(young);

/* 将所有从外部可达的对象移动到
* reachable 集合(ie. gc_refs > 0). 然后,
* 移动所有从reachable集合中的对象可达的对象
*/
gc_list_init(&reachable);
move_roots(young, &reachable);
move_root_reachable(&reachable);

/* 将不可达的对象移动到临时列表,
* 在这之后就可以分配新对象了 */
gc_list_init(&unreachable);
gc_list_move(young, &unreachable);

/* 将可达的对象移动到下一代 */
gc_list_merge(&reachable, old);

/* 移动从finalizers可达的对象, 我们还不能安全的删除他们
* . Python程序员注意不要去创建这样的东西。
* 对Python来说 finalizers 就是拥有 __del__ 方法的对象实例. */
gc_list_init(&finalizers);
move_finalizers(&unreachable, &finalizers);
move_finalizer_reachable(&finalizers);

/* 收集已发现的可回收的对象的统计数据,
* 然后打印调试信息 */
for (gc = unreachable.gc.gc_next; gc != &unreachable;
gc = gc->gc.gc_next) {
m++;
if (debug & DEBUG_COLLECTABLE) {
debug_cycle("collectable", FROM_GC(gc));
}
}
/* 对每个可回收的对象调用tp_clear. 它可以打破引用循环
* .也可能导致一些finalizer对象被释放*/
delete_garbage(&unreachable, old);

/* 收集不可回收对象的统计数据。
* 打印调试信息. */
for (gc = finalizers.gc.gc_next; gc != &finalizers;
gc = gc->gc.gc_next) {
n++;
if (debug & DEBUG_UNCOLLECTABLE) {
debug_cycle("uncollectable", FROM_GC(gc));
}
}
if (debug & DEBUG_STATS) {
if (m == 0 && n == 0) {
PySys_WriteStderr("gc: done.\n");
}
else {
PySys_WriteStderr(
"gc: done, %ld unreachable, %ld uncollectable.\n",
n+m, n);
}
}

/* 将finalizers加到一个可达的 Python 垃圾列表
* 程序员必须处理这个问题,如果他们非要创建这种结构的话. */
handle_finalizers(&finalizers, old);

if (PyErr_Occurred()) {
if (gc_str == NULL) {
gc_str = PyString_FromString("garbage collection");
}
PyErr_WriteUnraisable(gc_str);
Py_FatalError("unexpected exception during garbage collection");
}
allocated = 0;
return n+m;
}

注释够清晰吧(可能翻译有点烂,受不了的话就赶紧去下个leo玩吧)
下面一段是分代机制:
static long
collect_generations(void)
{
/* static就相当于是全局变量了
* collections0的意思就是第0代收集了多少次了
* threshold1的意思就是第0代需要收集多少次才开始收集第1代
* 这里可以先告诉大家threshold1=threshold2=10
* 中心思想就是:从0代开始收集,10次之后收集第1代,
* 又10次之后收集第2代,收集一次后回到第0代
*/
static long collections0 = 0;
static long collections1 = 0;
long n = 0;


if (collections1 > threshold2) {
generation = 2;
gc_list_merge(&_PyGC_generation0, &generation2);
gc_list_merge(&generation1, &generation2);
if (generation2.gc.gc_next != &generation2) {
n = collect(&generation2, &generation2);
}
collections1 = 0;
}
else if (collections0 > threshold1) {
generation = 1;
collections1++;
gc_list_merge(&_PyGC_generation0, &generation1);
if (generation1.gc.gc_next != &generation1) {
n = collect(&generation1, &generation2);
}
collections0 = 0;
}
else {
generation = 0;
collections0++;
if (_PyGC_generation0.gc.gc_next != &_PyGC_generation0) {
n = collect(&_PyGC_generation0, &generation1);
}
}
return n;
}

再往上走就是_PyObject_GC_Malloc了,这里大家可以看到垃圾回收是什么条件下触发的。

PyObject *
_PyObject_GC_Malloc(PyTypeObject *tp, int nitems)
{
PyObject *op;
const size_t basicsize = _PyObject_VAR_SIZE(tp, nitems);
#ifdef WITH_CYCLE_GC
const size_t nbytes = sizeof(PyGC_Head) + basicsize;
PyGC_Head *g = PyObject_MALLOC(nbytes);
if (g == NULL)
return (PyObject *)PyErr_NoMemory();
g->gc.gc_next = NULL;
allocated++;
/*
*allocated是个全局变量,记录从上次回收以来
*分配的对象的数目,而 threshold0=700
*/
if (allocated > threshold0 &&
enabled &&
threshold0 &&
!collecting &&
!PyErr_Occurred()) {
collecting = 1;
collect_generations();
collecting = 0;
}
op = FROM_GC(g);
#else
op = PyObject_MALLOC(basicsize);
if (op == NULL)
return (PyObject *)PyErr_NoMemory();

#endif
return op;
}

如果还要往上走,就是

PyObject *
_PyObject_GC_New(PyTypeObject *tp)
{
PyObject *op = _PyObject_GC_Malloc(tp, 0);
if (op != NULL)
op = PyObject_INIT(op, tp);
return op;
}

了,分配内存然后初始化,所有的对象模型都是一个样。

当然内部还有许多细节了,比如确定一个对象是否可达,处理引用循环,处理finalizers (想了半天还是不知道该怎么翻译这个词) 等等。大家自己用leo看吧,保证越看越爽,哈哈。






suppercabbage 发布于 15:14 | Trackback (0) | 编辑

Comments


Posted by kernel1983 (http://kjam.org) at 2006-06-26 17:39:17
leo在哪里有的下载?

google都看不到,嘿嘿真奇怪~~~
suppercabbage 回复 kernel1983 说:
http://webpages.charter.net/edreamleo/front.html
google 当然有,搜 leo python 第一条就是 :)
(2006-06-26 17:53:35)


Add Comment


姓名:

Email:

主页: