我用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
将调用链接在一起时调用返回的析构函数过早。为了观察,我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)
我现在已经花了几天的时间,我几乎没有想法,所以真的任何关于如何解决这个问题的见解将不胜感激。