在使用回调将Python对象传递给C时,如何避免内存泄漏?

2024-10-04 03:20:57 发布

您现在位置:Python中文网/ 问答频道 /正文

为了避免在下面描述的sutuation中发生内存泄漏,我想直接从Python调用Py\u 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函数调用它。这种解决方案至少有两个缺点:

  1. 仅为一个函数创建dll似乎过于复杂

  2. C代码必须针对特定版本的Python进行编译,而不是使用运行Python代码的Python版本。请注意,我需要这个在Windows上工作,其中dll不能包含未定义的全局变量。


Tags: theto对象函数代码pyobjectit