gpt4 book ai didi

php - 过早收集资源垃圾

转载 作者:可可西里 更新时间:2023-11-01 12:21:36 24 4
gpt4 key购买 nike

我用 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)

我已经在这个问题上花了几天时间,但我几乎没有想法,所以非常感谢任何关于如何解决这个问题的见解。

最佳答案

This原来是类似调试问题段错误的问题的一部分。 (Artefacto 说的)

关于php - 过早收集资源垃圾,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3526067/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com