Правильная циклическая сборка мусора в модулях расширения

В двух разделах документа Python 2.7 упоминается добавление поддержки циклической сборки мусора (CGC) для объектов контейнера, определенных в модулях расширения.

Справочное руководство по API Python / C дает два правила:

  1. Память для объекта должна быть выделена с помощью PyObject_GC_New() или PyObject_GC_NewVar() .
  2. После того, как все поля, которые могут содержать ссылки на другие контейнеры, будут инициализированы, он должен вызвать PyObject_GC_Track() .

В то время как в расширении и встраивании интерпретатора Python для примера Noddy кажется, что добавление флага Py_TPFLAGS_HAVE_GC и заполнение tp_traverse и tp_clear слотов будет достаточным для поддержки CGC. И два вышеприведенных правила НЕ применяются практически.

Когда я модифицировал пример Noddy чтобы фактически следовать правилам PyObject_GC_New() / PyObject_GC_Del() и PyObject_Track() / PyObject_GC_UnTrack() , он неожиданно поднял ошибку утверждения, говоря:

Модули / gcmodule.c: 348: visit_decref: утверждение «gc-> gc.gc_refs! = 0» не выполнено. пересчет был слишком мал

Это приводит к моей путанице в правильном / безопасном способе реализации CGC. Может ли кто-нибудь давать советы или, предпочтительно, опрятный пример контейнерного объекта с поддержкой CGC?

2 Solutions collect form web for “Правильная циклическая сборка мусора в модулях расширения”

В большинстве нормальных случаев вам не нужно делать слежение / выслеживание самостоятельно. Это описано в документации, однако это не делается четко. В случае примера Noddy вы определенно этого не делаете.

Короткий вариант заключается в том, что TypeObject содержит два указателя на функции: tp_alloc и tp_free . По умолчанию tp_alloc вызывает все правильные функции при создании класса (если установлен Py_TPFLAGS_HAVE_GC ), а tp_free освобождает класс от уничтожения.

В документации Noddy говорится (в конце раздела):

Это в значительной степени. Если бы мы написали пользовательские tp_alloc или tp_free , нам нужно было бы их модифицировать для сбора циклических мусора. Большинство расширений будут использовать предоставленные версии автоматически.

К сожалению, одно место, которое не дает понять, что вам не нужно это делать самостоятельно, – это документация Supporting Cyclic Garbage Collection .


Деталь:

Noddy выделяются с помощью функции Noddy_new помещенной в слоты tp_new объекта TypeObject . Согласно документации , главное, что должна выполнить «новая» функция, – это tp_alloc слот tp_alloc . Обычно вы не пишете tp_alloc , а по умолчанию – PyType_GenericAlloc() .

Глядя на PyType_GenericAlloc() в источнике Python, отображается ряд разделов, где он изменяется на основе PyType_IS_GC(type) . Сначала он вызывает _PyObject_GC_Malloc вместо PyObject_Malloc , а второй вызывает _PyObject_GC_TRACK(obj) . [Обратите внимание, что все, что PyObject_New действительно делает, это вызов PyObject_Malloc а затем tp_init .]

Аналогично, при освобождении вы вызываете слот tp_free , который автоматически устанавливается в PyObject_GC_Del для классов с Py_TPFLAGS_HAVE_GC . PyObject_GC_Del включает в себя код, который выполняет то же самое, что и PyObject_GC_UnTrack поэтому вызов для проверки не нужен.

Я сам не очень опытен в C API, чтобы дать вам какие-либо советы, но примеров реализации самих контейнеров Python достаточно.

Лично я начинаю с реализации кортежа во-первых, поскольку он неизменен: Objects / tupleobject.c . Затем перейдите к list dict , list и set реализации для дальнейших заметок в изменяемых контейнерах:

  • Объекты / dictobject.c
  • Объекты / listobject.c
  • Объекты / setobject.c

Я не могу не заметить, что есть вызовы PyObject_GC_New() , PyObject_GC_NewVar() и PyObject_GC_Track() всем протяжении, а также набор Py_TPFLAGS_HAVE_GC .

  • Создание объекта с использованием API Python C
  • почему я не смог построить sqlite3 при сборке python?
  • Импорт и использование стандартного модуля Python из внутреннего расширения Python C
  • Компилятор не может найти Py_InitModule () .. он устарел, и если да, то что я должен использовать?
  • Как я могу написать функцию C, которая принимает либо int, либо float?
  • Запуск Cython в Windows x64 - фатальная ошибка C1083: невозможно открыть файл include: basetsd.h: нет такого файла или каталога
  • Аспектно-ориентированное программирование (AOP) в Python
  • Могу ли я использовать скомпилированные Python-файлы MinGW вместе с скомпилированными Visual C ++?
  •  
    Interesting Posts for Van-Lav

    uWSGI, ImportError: Нет модуля с именем site на Ubuntu

    Вызовите скрипт python из ruby

    В scikit узнать, как обрабатывать данные, смешанные с численным и номинальным значением?

    Python и py2exe – Имплантируемый импорт модулей

    Определение и реализация алгоритма трендов в Django

    Терминал Pycharm не изменяет версию Python, соответствующую версии Python, в Project Interpreter

    Является ли эта строка Base64? Как я могу узнать, что такое кодировка?

    "TypeError: Невозможно преобразовать объект NoneType в str неявно", когда var должен иметь значение

    Преобразование нескольких столбцов в категории в Pandas. подать заявление?

    Многопроцессорная обработка занимает больше времени, чем многопроцессорность – Python

    Как получить значение из переменной тензора anano, поддерживаемой общей переменной?

    Django-models: использование поля из внешнего ключа

    Высокое использование процессора Python

    Создание класса внутри функции и доступ к функции, определенной в области содержащейся функции

    вычисление dask не выполняется параллельно

    Python - лучший язык программирования в мире.