Ресурс мусора собран слишком рано - PullRequest
9 голосов
/ 20 августа 2010

Я создал расширение 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)

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

1 Ответ

1 голос
/ 17 сентября 2010

Это оказалось частью проблемы с подобной проблемой отладки segfaulting. (что сказал Артефакто)

...