Как избежать утечки памяти, когда объекты Python передаются в C с помощью обратных вызовов? - PullRequest
0 голосов
/ 18 февраля 2019

Чтобы избежать утечки памяти в описанной ниже ситуации, я хотел бы вызвать 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) ивызовите это из функции уничтожения выше.Это решение имеет по крайней мере два недостатка:

  1. Кажется слишком сложным создать dll только для одной функции

  2. Код C должен был быбыть скомпилированным для конкретной версии Python, вместо того, чтобы использовать какую-либо версию Python, на которой выполняется мой код Python.Обратите внимание, что это необходимо для работы в Windows, где DLL не может содержать неопределенные глобальные переменные.

...