LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 276|回复: 0

终结和内存释放

[复制链接]
发表于 2024-1-18 18:36:48 | 显示全部楼层 |阅读模式

终结和内存释放
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 类型方法。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表