c语言和python垃圾回收制,使用C语言编写Python扩展5——垃圾回收管理

本文深入探讨了Python中的垃圾回收机制,特别是对于循环引用的处理。通过一个C扩展模块的例子,展示了如何使对象支持垃圾回收,包括设置`Py_TPFLAGS_HAVE_GC`标志,实现`tp_traverse`和`tp_clear`方法,以及在`tp_new`和`tp_dealloc`函数中的应用。最后,通过Python代码测试了垃圾回收的效果。
摘要由CSDN通过智能技术生成

上一节介绍了创建一个具有属性的类,由于对象具有属性数据,因此在进行内存管理时要多加注意。这一节就介绍一下Python的垃圾回收管理。

在Python中垃圾回收主要是靠的计数引用方法,但是单凭计数引用还是不够的。先看看下面这段Python代码。

n = []

m = []

n.append(m)

m.append(n)

del m

del n

如果只靠计数引用的话执行上面这段代码之后n和m都不能被回收,因为它们的引用计算值都不为0。

像上面例子这样相互循环引用称作循环引用垃圾,在Python中有循环垃圾回收器(cyclic-garbage collector)专门用于回收此类计数引用无法处理的垃圾内存。

接着上一节的例子,继续编辑noddy.c。

为了让该对象类型支持垃圾回收,将PyTypeObject的tp_flags字段增加Py_TPFLAGS_HAVE_GC这个标志位。同时与GC(Garbage Collection)相关的tp_traverse和tp_clear这两个字段也要设置。

tp_traverse是用于垃圾回收器(garbage collector)遍历该实例对象中所有需要回收的属性对象。

tp_clear是用于清除内部各个属性对象的。

首先定义tp_traverse和tp_clear所对应的函数:

static int Noddy_traverse(noddy_NoddyObject self, visitproc visit, voidarg)

{

Py_VISIT(self->first);

Py_VISIT(self->last);

return 0;

}

static int Noddy_clear(noddy_NoddyObject self)

{

Py_CLEAR(self->first);

Py_CLEAR(self->last);

return 0;

}

Py_VISIT和Py_CLEAR是两个宏,简化了visit操作和clear操作。

然后再修改noddy_NoddyType结构体定义:

static PyTypeObject noddy_NoddyType = {

PyObject_HEAD_INIT(NULL)

0, /ob_size/

“noddy.Noddy”, /tp_name/

sizeof(noddy_NoddyObject), /tp_basicsize/

0, /tp_itemsize/

(destructor)Noddy_dealloc, /tp_dealloc/

0, /tp_print/

0, /tp_getattr/

0, /tp_setattr/

0, /tp_compare/

0, /tp_repr/

0, /tp_as_number/

0, /tp_as_sequence/

0, /tp_as_mapping/

0, /tp_hash /

0, /tp_call/

0, /tp_str/

0, /tp_getattro/

0, /tp_setattro/

0, /tp_as_buffer/

Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /tp_flags/

“Noddy objects”, /tp_doc/

(traverseproc)Noddy_traverse, / tp_traverse /

(inquiry)Noddy_clear, / tp_clear /

0, / tp_richcompare /

0, / tp_weaklistoffset /

0, / tp_iter /

0, / tp_iternext /

Noddy_methods, / tp_methods /

Noddy_members, / tp_members /

0, / tp_getset /

0, / tp_base /

0, / tp_dict /

0, / tp_descr_get /

0, / tp_descr_set /

0, / tp_dictoffset /

(initproc)Noddy_init, / tp_init /

0, / tp_alloc /

Noddy_new, / tp_new /

};

注意:

Python的官方手册中说道如果设置了Py_TPFLAGS_HAVE_GC这个标志位的话,那么就必须使用PyObject_GC_New这个函数来创建实例对象,使用PyObject_GC_Del来销毁已创建了的实例对象。

使用PyObject_GC_New创建实例对象之后再用PyObject_GC_Track将该实例添加到垃圾回收器所跟踪的对象集合中去。

在对象销毁时再执行PyObject_GC_UnTrack和PyObject_GC_Del函数。

然后再修改tp_new函数和tp_dealloc函数:

static PyObject Noddy_new(PyTypeObject type, PyObjectargs, PyObject kwds)

{

noddy_NoddyObjectself;

self = (noddy_NoddyObject)PyObject_GC_New(noddy_NoddyObject, type);

if (self != NULL) {

PyObject_GC_Track(self);

self->first = PyString_FromString(“”);

if (self->first == NULL)

{

Py_DECREF(self);

return NULL;

}

self->last = PyString_FromString(“”);

if (self->last == NULL)

{

Py_DECREF(self);

return NULL;

}

self->number = 0;

}

return (PyObject)self;

}

static void Noddy_dealloc(noddy_NoddyObject* self)

{

PyObject_GC_UnTrack(self);

Noddy_clear(self);

PyObject_GC_Del(self);

}

最后再写一段Python程序来测试下该模块:

import gc

import noddy

gc.set_debug(gc.DEBUG_STATS | gc.DEBUG_LEAK)

o = noddy.Noddy()

l = [o]

o.first = l

del l

del o

gc.collect()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值