如何正确使用PyObject_Malloc/Realloc避免内存泄漏及指针释放报错
PyObject内存分配接口的正确使用方法
问题背景
参考CPython源码对PyObject_Realloc的说明:
对于非空指针p,调用
PyObject_Realloc(p, 0)时,既不会返回NULL值,也不会释放p指向的内存空间。
据此认为该函数不会主动释放内存,在排查内存泄漏时编写了如下调整内存大小的逻辑:
PyLongObject *new = (PyLongObject *) PyObject_Realloc(obj, new_size); if (new == NULL) { return PyErr_NoMemory(); } if (new != obj) { PyObject_Free(obj); } obj = new;
修改后程序触发malloc报错:pointer being freed was not allocated,需要明确搭配使用PyObject_Malloc、PyObject_Realloc的正确流程,避免内存泄漏。
报错根源
代码中手动调用PyObject_Free(obj)的逻辑是触发报错的核心原因。PyObject_Realloc的常规场景语义与标准C库realloc完全一致:当申请的新内存大小大于0时,函数会自动完成原内存块的尺寸调整、内容拷贝、原内存块回收的全流程,原指针的内存所有权完全由函数内部接管,调用者无需手动释放原指针。
此时再对已经被函数内部回收的旧指针调用释放接口,属于二次释放操作,会触发分配器的校验逻辑,抛出“指针未被分配就被释放”的错误。
易混淆的边界规则
你看到的文档说明仅适用于申请内存大小为0的特殊场景:
- 当传入非空原指针,且申请大小为0时,函数不会释放原指针指向的内存,会直接返回原指针地址,这是唯一需要手动处理原内存的realloc场景
- 其他所有常规尺寸的调整场景下,函数都会自动完成原内存的回收,不存在“不主动释放内存”的问题
正确操作流程
- 内存分配:直接调用
PyObject_Malloc(申请大小),将返回的有效指针存入对应的变量 - 尺寸调整:直接调用
PyObject_Realloc(原有指针, 新的申请大小),将返回的新指针直接替换原有变量的值,无需手动释放旧指针。正确的调整代码示例:PyLongObject *new = (PyLongObject *) PyObject_Realloc(obj, new_size); if (new == NULL) { return PyErr_NoMemory(); } obj = new; - 常规内存释放:对当前持有的有效指针调用
PyObject_Free即可,无需追溯指针的历史变更过程 - 0尺寸场景处理:当需要将内存块收缩到0大小时,不能依赖realloc的自动回收逻辑,需要直接调用
PyObject_Free释放内存,并将指针置空避免野指针
内存泄漏规避要点
- 严格遵守分配器配对规则:所有通过
PyObject_Malloc、PyObject_Realloc分配的内存,必须使用PyObject_Free释放,禁止和标准C库的malloc、realloc、free混用,否则会因内存块元数据不兼容触发报错或泄漏 - 非0尺寸的realloc流程中,不要手动释放原指针,避免二次释放
- 释放内存时直接操作当前持有的有效指针,不要依赖边界场景下的自动回收逻辑
内容的提问来源于stack exchange,提问作者user3310334
相关产品推荐
相关产品推荐

