资源垃圾收集得太早

Ed *_*zur 9 php swig garbage-collection php-extension chaining

我已经使用SWIG创建了一个PHP扩展,一切正常,但是当链接方法调用时,我正在观察一些奇怪的垃圾收集行为.例如,这有效:

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

但这段错误:

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

唯一的区别是第一个创建$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));
Run Code Online (Sandbox Code Playgroud)

再次,这段错误:

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

同样,唯一的区别是第一个创建$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
Run Code Online (Sandbox Code Playgroud)

---在脚本的末尾打印,以便能够区分脚本执行期间发生的事情以及之后发生的事情.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)
Run Code Online (Sandbox Code Playgroud)

如果没有InvocationResponse_results保存的返回值$results,很高兴在执行之前收集垃圾甚至离开调用链(在Tables_get和之间Table_iterator),这很快就会导致问题,最终导致seg故障.

我还在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)
Run Code Online (Sandbox Code Playgroud)

$row链接:

row: (refcount=1, is_ref=0)=resource(21) of type (_p_voltdb__Row)
Run Code Online (Sandbox Code Playgroud)

我现在已经花了几天时间,我只是出于想法,所以我们非常感激任何关于如何解决这个问题的见解.