Я создал расширение 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));
Единственное отличие состоит в том, что первый создает $results
, а второй объединяет вызовы вместе.
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
Я напечатал ---
в конце сценария, чтобы иметь возможность различать, что происходит во время выполнения сценария и что происходит после. Hola Mundo
от 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
не сохранено в $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)
Я потратил пару дней на это сейчас, и у меня почти нет идей, так что на самом деле любое понимание того, как решить эту проблему, будет с благодарностью.