资源垃圾收集得太早

时间:2010-08-19 20:44:08

标签: php garbage-collection swig php-extension chaining

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

$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的析构函数。为了观察,我在暴露的C ++函数及其析构函数的顶部插入了std::cout语句。这是没有链接的输出:

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_getTable_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 个答案:

答案 0 :(得分:1)

This被证明是类似调试问题segssion的问题的一部分。 (Artefacto说的话)