Python C扩展:内部空闲列表何时释放?GC后需清理吗?
扩展模块空闲列表的GC后清理问题
是否需要在完整垃圾回收后清理?
需要。扩展模块的空闲列表中保留的对象会被内部链表引用,不会被垃圾回收器回收。如果长期不清理,这些对象会持续占用内存,尤其在频繁创建临时对象的场景下,会导致内存占用居高不下,无法有效释放。
如何操作?
1. 实现清理空闲列表的C函数
扩展模块需自行编写清理空闲列表的逻辑,示例:
static int MyModule_ClearFreeList(void) { // 重置自定义空闲链表、释放保留对象等操作 my_free_list_head = NULL; return 0; }
2. 触发清理的两种方式
方式一:Python层面GC回调(兼容所有Python版本)
- 先在扩展模块中把清理函数包装为Python可调用方法:
static PyObject *my_module_clear_free_list(PyObject *self, PyObject *args) { MyModule_ClearFreeList(); Py_RETURN_NONE; } static PyMethodDef MyModuleMethods[] = { {"clear_free_list", my_module_clear_free_list, METH_NOARGS, "Clear the free list of my module"}, {NULL, NULL, 0, NULL} }; - 在Python代码中注册GC回调,检测最高代回收并触发清理:
import gc def gc_callback(phase, info): if phase == "stop" and info["generation"] == gc.get_threshold()[-1] - 1: import my_module my_module.clear_free_list() gc.callbacks.append(gc_callback)
方式二:C层面GC回调(Python 3.9+)
Python 3.9及以上提供PyGC_RegisterCallback API,可直接在C代码中监听GC事件:
static void gc_callback(PyGC_Event event, PyObject *info) { if (event == PyGC_EVENT_STOP) { PyObject *generation_obj = PyDict_GetItemString(info, "generation"); if (generation_obj && PyLong_AsLong(generation_obj) == NUM_GENERATIONS - 1) { MyModule_ClearFreeList(); } Py_XDECREF(generation_obj); } } // 模块初始化时注册回调 PyMODINIT_FUNC PyInit_my_module(void) { PyObject *m = PyModule_Create(&MyModuleDef); if (!m) return NULL; PyGC_RegisterCallback(gc_callback); return m; }
垃圾回收器是否提供相应钩子?
- Python 3.9及以上:提供
PyGC_RegisterCallbackC API钩子,可直接在C层面监听GC的开始、结束等阶段事件。 - Python 3.8及更早版本:无C层面直接钩子,但可通过标准库
gc.callbacks注册Python回调函数,间接实现最高代回收后的清理逻辑。
内容的提问来源于stack exchange,提问作者Suen
相关产品推荐
相关产品推荐

