终结和内存释放
destructor tp_dealloc;
当您的类型实例的引用计数减少为零并且Python解释器想要回收它时,将调用此函数。如果你的类型有内存可供释放或执行其他清理,你可以把它放在这里。 对象本身也需要在这里释放。 以下是此函数的示例:
static void
newdatatype_dealloc(newdatatypeobject *obj)
{
free(obj->obj_UnderlyingDatatypePtr);
Py_TYPE(obj)->tp_free((PyObject *)obj);
}
如果你的类型支持垃圾回收,则析构器应当在清理任何成员字段之前调用 PyObject_GC_UnTrack():
static void
newdatatype_dealloc(newdatatypeobject *obj)
{
PyObject_GC_UnTrack(obj);
Py_CLEAR(obj->other_obj);
...
Py_TYPE(obj)->tp_free((PyObject *)obj);
}
一个重要的释放器函数实现要求是把所有未决异常放着不动。这很重要是因为释放器会被解释器频繁的调用,当栈异常退出时(而非正常返回),不会有任何办法保护释放器看到一个异常尚未被设置。此事释放器的任何行为都会导致额外增加的Python代码来检查异常是否被设置。这可能导致解释器的误导性错误。正确的保护方法是,在任何不安全的操作前,保存未决异常,然后在其完成后恢复。者可以通过 PyErr_Fetch() 和 PyErr_Restore() 函数来实现:
static void
my_dealloc(PyObject *obj)
{
MyObject *self = (MyObject *) obj;
PyObject *cbresult;
if (self->my_callback != NULL) {
PyObject *err_type, *err_value, *err_traceback;
/* This saves the current exception state */
PyErr_Fetch(&err_type, &err_value, &err_traceback);
cbresult = PyObject_CallNoArgs(self->my_callback);
if (cbresult == NULL)
PyErr_WriteUnraisable(self->my_callback);
else
Py_DECREF(cbresult);
/* This restores the saved exception state */
PyErr_Restore(err_type, err_value, err_traceback);
Py_DECREF(self->my_callback);
}
Py_TYPE(obj)->tp_free((PyObject*)self);
}
备注 你能在释放器函数中安全执行的操作是有限的。 首先,如果你的类型支持垃圾回收 (使用 tp_traverse 和/或 tp_clear),对象的部分成员可以在调用 tp_dealloc 时被清空或终结。 其次,在 tp_dealloc 中,你的对象将处于不稳定状态:它的引用计数等于零。 任何对非琐碎对象或 API 的调用 (如上面的示例所做的) 最终都可能会再次调用 tp_dealloc,导致双重释放并发生崩溃。
从 Python 3.4 开始,推荐不要在 tp_dealloc 放复杂的终结代码,而是使用新的 tp_finalize 类型方法。 |