16 мая 2014 г.

PySide: Internal C++ object already deleted

Эта ошибка возникает в следующем случае:
  • Имеется Python(PySide)-объект с ненулевым счетчиком ссылок, который привязан к некоторому C++-объекту QObject.
  • Где-то в C++-коде C++-объект уничтожается без ведома Python.
  • Где-то в Python-коде происходит обращение к Python-объекту, который теперь ссылается на уничтоженный QObject.

Наиболее вероятный сценарий уничтожения QObject в C++ без ведома Python такой:
  • По какой-то причине из Python или из C++ было запущено уничтожение родительского объекта QObject.
  • Управление получил C++-деструктор родительского QObject, который уничтожил все дочерние C++-объекты QObject.
  • Ссылки на эти дочерние объекты из Python остались висячими.

Соотвественно, при появлении такой ошибки стоит проверить, не были ли уничтожены родительские объекты.

Если объект был уничтожен совершенно внезапно (например, при нажатии никак не связанной с ним кнопки), возможно родительские объекты были удалены сборщиком мусора, который просто не был запущен до этого.

Отлаживать такую ситуацию довольно просто:
  • Собираем Python с отладочными символами.
  • Запускаем Python под GDB.
  • Ставим breakpoint на С++-деструктор того QObject, который внезапно удаляется.
  • Смотрим C++-backtrace (команда bt) и наслаждаемся поддержкой Python в GDB, которая позволяет распечатывать все PyObject.
  • Смотрим Python-backtrace (команда py-bt).

Если дело в сборщике мусора, то по backtrace-ам можно увидеть, начиная с какого объекта началось удаление.

Если GDB не распечатывает PyObject и py-bt не работает, скорее всего Python собран без отладочных символов.
Если GDB периодически печатает ошибку:

Python Exception <type 'exceptions.TypeError'> object of type 'FakeRepr' has no len()

то можно воспользоваться патчем.

Комментариев нет:

Отправить комментарий