Чтобы избежать утечки памяти в описанной ниже ситуации, я хотел бы вызвать Py_DecRef непосредственно из Python.Есть ли способ сделать это?Есть ли лучшее решение для этой проблемы?
Я использую 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?
Один из вариантов - создать функцию C, которая вызывает Py_DecRef, скомпилировать эту функцию C в dll (или около того для Linux) ивызовите это из функции уничтожения выше.Это решение имеет по крайней мере два недостатка:
Кажется слишком сложным создать dll только для одной функции
Код C должен был быбыть скомпилированным для конкретной версии Python, вместо того, чтобы использовать какую-либо версию Python, на которой выполняется мой код Python.Обратите внимание, что это необходимо для работы в Windows, где DLL не может содержать неопределенные глобальные переменные.