LINUX.ORG.RU

[py3k] хитрый вопрос про счётчик ссылок


0

0

Привет, неспящий лор!
Есть такой простой код:

log_debug("refcnt before call %d", Py_REFCNT(self));
py_result = PyObject_CallMethod(self, "on_recv", "(y#)", recvbuf, sended_bytes);
log_debug("refcnt after call: %d\n", Py_REFCNT(self));

Если унаследовать базовый C-класс из питона, переопределить метод on_recv и вызвать эксепшн то ob_refcnt возрастёт на единицу. Если же on_recv не переопределять и вызвать эксепшн в C-коде то никаких проблем нет.

Вопрос: кто увеличивает ob_refcnt и как с этим бороться?
Вызов PyErr_Print() ничего не меняет.

★★★★★
Ответ на: комментарий от tailgunner

> Что-то непонятно.

Всё просто, почему-то при эксепшене кто-то делает Py_INCREF() на инстанс при указанных условиях. Если эксепшена не происходит то всё работает как ожидается.

ушёл учить таблицу неправельных глаголов

true_admin ★★★★★
() автор топика
Ответ на: комментарий от true_admin

> неправельных глаголов

Русский язык тоже повтори!

anonymous
()

То есть: 1) наследуется определенный в Си-модуле класс, 2) вызывается его метод, 3) в методе бросается исключение. И разность в поведении: если исключение бросается (возвращается, на самом деле) из метода на Си, то счетчик ссылок _не_ увеличивается; а если исключение бросается из метода на Питоне, то увеличивается. Так?

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Не совсем.
1) Наследуется C-класс.
2) Метод on_recv переопределяется в "питоне"
3) C-класс(инстанс) вызывает свой метод on_recv, но т.к. он переопределён, то вызывается на самом деле питоновский on_recv

Всё работает нормально.
Но, если питоновский код выплюнет эксепшн то счётчик ссылок на инстанс увеличивается на единицу. Вопрос в том почему это происходит.

Т.е. вот такой код будет работать нормально:
http://dpaste.com/104490/

А вот такой сделает Py_INCREF(self) на C-инстанс(на self):
http://dpaste.com/104491/

true_admin ★★★★★
() автор топика
Ответ на: комментарий от true_admin

Тщательный анализ показывает что всё же где-то неправ я. Напишу как только разберусь.

true_admin ★★★★★
() автор топика
Ответ на: комментарий от true_admin

>почему это происходит.

Очевидная догадка: Exception, или то, что его обрабатывает, создаёт новую ссылку на "текущий" объект.

DonkeyHot ★★★★★
()
Ответ на: комментарий от DonkeyHot

Не, весь обработчик exception это PyErr_Print()

Меня тут ещё gdb научили правильно пользоваться, теперь дело пошло веселее. Короче, PyEval_EvalCodeEx делает SETLOCAL, а вот что там дальше происходит не успеваю посмотреть. Завтра, надеюсь, доковыряю и напишу.

true_admin ★★★★★
() автор топика

Всем спасибо кто пытался помочь. Похоже, проблема в PyErr_Print(), он не вызывает frame_dealloc(или что там нужно высвободить). Более подробно проблему описывать не буду потому что сам в этих stack frame-ах плохо понимаю. PyErr_Clear() лечит проблему.

Напишу багрепорт. Тут или в документации баг или в питоне (или (unlikely) в голове).

Пять дней ипался...

true_admin ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.