Мусор ресурсов собран слишком рано

Я создал расширение PHP с SWIG и все работает нормально, но я наблюдаю некоторое странное поведение при сборке мусора, когда вызовы метода цепочки. Например, это работает:

$results = $response->results();
$row = $results->get(0)->iterator()->next();
printf('%s %s' . "\n", $row->getString(0), $row->getString(1));

Но эта ошибка сегмента:

$row = $response->results()->get(0)->iterator()->next();
printf('%s %s' . "\n", $row->getString(0), $row->getString(1));

Единственное отличие состоит в том, что первый создает результаты $ , в то время как второй объединяет вызовы вместе.

SWIG фактически выставляет только функции в PHP и генерирует прокси-классы PHP для взаимодействия с ними. Эти прокси-классы в основном содержат ресурс, который передается каждой из представленных функций вместе с другими аргументами, которые эти функции обычно принимают. Думая, что, возможно, эти прокси-классы были проблемой, я переработал код, чтобы обойти их и вместо этого напрямую использовать предоставляемые функции. Как и прежде, это работает:

$results = InvocationResponse_results($response->_cPtr);
$row = TableIterator_next(Table_iterator(Tables_get($results, 0)));
printf('%s %s' . "\n", Row_getString($row, 0), Row_getString($row, 1));

И снова, этот сегмент неисправен:

$row = TableIterator_next(Table_iterator(Tables_get(InvocationResponse_results($response->_cPtr), 0)));
printf('%s %s' . "\n", Row_getString($row, 0), Row_getString($row, 1));

Опять-таки, единственное отличие состоит в том, что первый создает $ results , а второй объединяет вызовы вместе.

В На этом этапе я провел некоторое время отладки в gdb / valgrind и определил, что деструктор для того, что возвращает InvocationResponse_results , вызывается слишком рано при объединении вызовов в цепочку. Чтобы наблюдать, я вставил операторы std :: cout в вершины представленных функций C ++ и их деструкторов. Это вывод без цепочки:

InvocationResponse_results()
Tables_get()
Table_iterator()
TableIterator_next()
__wrap_delete_TableIterator
Row_getString()
Row_getString()
Hola Mundo
---
__wrap_delete_InvocationResponse
__wrap_delete_Row
__wrap_delete_Tables

Я напечатал --- в конце скрипта, чтобы иметь возможность различать, что происходит во время выполнения скрипта и что происходит после. Хола Мундо из printf . Остальное из C ++. Как видите, все вызывается в ожидаемом порядке. Деструкторы вызываются только после выполнения скрипта, хотя деструктор TableIterator вызывается раньше, чем я ожидал. Однако это не вызвало каких-либо проблем и, вероятно, не связано. Теперь сравните это с выводом с цепочкой:

InvocationResponse_results()
Tables_get()
__wrap_delete_Tables
Table_iterator()
TableIterator_next()
__wrap_delete_TableIterator
Row_getString()
Segmentation fault (core dumped)

Без возврата возвращаемого значения InvocationResponse_results в результаты $ , он удачно собирает мусор до того, как выполнение даже выходит из цепочки вызовов (между Tables_get и Table_iterator ), и это быстро вызывает проблемы в будущем, что в конечном итоге приводит к ошибке сегмента.

Я также проверял подсчет ссылок, используя xdebug_debug_zval () в разных местах, но ничего необычного не заметил. Вот его результаты для $ results и $ row без цепочки:

results: (refcount=1, is_ref=0)=resource(18) of type (_p_std__vectorT_voltdb__Table_t)
row: (refcount=1, is_ref=0)=resource(21) of type (_p_voltdb__Row)

И для $ row с цепочкой:

row: (refcount=1, is_ref=0)=resource(21) of type (_p_voltdb__Row)

Я потратил пару дней на этом сейчас, и у меня почти нет идей, так что на самом деле любое понимание того, как решить эту проблему, будет с благодарностью.

9
задан Chadwick 11 September 2010 в 06:42
поделиться