python - 使用回调将 Python 对象传递给 C 时如何避免内存泄漏?
问题描述
为了避免下面描述的内存泄漏,我想直接从 Python 调用 Py_DecRef。有没有办法做到这一点?这个问题有更好的解决方案吗?
我正在使用 ctypes 将我的 Python 代码连接到我没有代码的 C 库。C 库不是为 Python 编写的,因此它对 Python 对象一无所知。
C 库使用两个回调:第一个创建一个对象并返回一个指向它的 void* 指针,第二个获取指针作为参数并应该销毁它。在 C 头文件中,这些回调函数的类型定义如下:
typedef void* (*CreateCallback)();
typedef void (*DestroyCallback)(void*);
这些回调可以在 Python 中定义,如下所示(简化代码)。如注释中所述,当前代码存在内存泄漏。
import ctypes
CreateCallback = ctypes.CFUNCTYPE(ctypes.py_object)
DestroyCallback = ctypes.CFUNCTYPE(None, ctypes.py_object)
class Object:
pass # In the real application, this contains more code
@CreateCallback
def create():
return Object()
# Ctypes correctly increments the reference count of the
# object, to make sure it does not get garbage collected
# while the C code holds a reference to it.
@DestroyCallback
def destroy(object):
pass
# Above, the reference count of the object should be
# decremented, because the C code no longer holds a
# reference to it. However, Ctypes does not know this so
# cannot do it automatically. How can I do this from
# Python? Is it possible to call Py_DecRef or similar
# directly from Python?
一种选择是创建一个调用 Py_DecRef 的 C 函数,将该 C 函数编译成一个 dll(对于 Linux 来说是这样),然后从上面的 destroy 函数中调用它。该解决方案至少有两个缺点:
只为一个函数创建一个 dll 似乎过于复杂
C 代码必须针对特定版本的 Python 进行编译,而不是使用运行我的 Python 代码的任何版本的 Python。请注意,我需要它在 Windows 上工作,其中 dll 不能包含未定义的全局变量。
解决方案
推荐阅读
- discord - 如何让我的不和谐机器人响应没有前缀的消息
- amazon-web-services - aws lambda 函数和对应的 IAM 角色,用于在 CloudFormation 中停止和启动 EC2 实例
- angular - 打开角度模态弹出窗口时未选中角度材料单选按钮
- r - In shiny, how to have a new actionButton when a different variable is selected?
- git - 之前将开发合并到我的功能分支后,你能 git 交互式 rebase squash 吗?
- php - Magento 报告问题 - 只有过滤器选项可用,没有表格显示
- java - 如何使用mapstruct将对象映射为字段?
- oracle - 需要更新 sqlplus 中的泰米尔语字体
- oracle - 如何使用 PL/SQL 代码在 Apex Oracle 中显示十进制值
- python - pip 在安装兼容的包版本时是否考虑到实际的 Python 版本?