以下是我创建的测试函数(针对 PHP 7.1)。
PHP_FUNCTION(tsc_test3)
{
zend_string *cnA;
zend_class_entry *ceA;
// $ret = new ClsA();
cnA = zend_string_init("ClsA", 4, 0);
ceA = zend_fetch_class(cnA, ZEND_FETCH_CLASS_DEFAULT);
zend_string_release(cnA);
object_init_ex(return_value, ceA);
// $ret->propA = $ret;
zval objA;
ZVAL_COPY(&objA, return_value);
zend_update_property(ceA, return_value, "propA", 5, &objA);
zval_ptr_dtor(&objA);
return;
}
正如评论中所建议的,它返回一个 ClsA
的循环对象。
以下是该功能的测试PHP程序。
<?php
class ClsA {
public $propA = 1;
}
$x = tsc_test3();
echo "DUMP1 ----\n";
var_dump($x);
for ($i = 0; $i < 10; $i++) {
echo "Memory usage: ". memory_get_usage(). "\n";
$x = tsc_test3();
}
echo "DUMP2 ----\n";
var_dump($x);
$x->propA = null;
echo "DUMP3 ----\n";
var_dump($x);
这是 PHP 代码的输出。
DUMP1 ---- object(ClsA)#1 (1) { ["propA"]=> *RECURSION* } Memory usage: 351336 Memory usage: 351392 Memory usage: 351448 Memory usage: 351504 Memory usage: 351560 Memory usage: 351616 Memory usage: 351672 Memory usage: 351728 Memory usage: 351784 Memory usage: 351840 DUMP2 ---- object(ClsA)#11 (1) { ["propA"]=> *RECURSION* } DUMP3 ---- object(ClsA)#11 (1) { ["propA"]=> NULL }
The var_dump()
result looks fine, but memory usage constantly increases.
When I use ZVAL_COPY_VALUE
instead of ZVAL_COPY
, the memory usage doesn't increase, but it produces a weird output in DUMP3.
DUMP3 ---- *RECURSION*
May be the function returns a corrupted object.
Can anybody tell me what's wrong in the extension function?
Edit1: Just after posting the question I noticed memory_get_usage(true)
doesn't increase. Is this the mistake I made?
Edit2: The following PHP program (pure PHP, no extension) shows increasing memory usage. Is this a PHP bug or am I misunderstanding something? I'm using PHP 7.1.28.
<?php
class ClsA {
public $propA = 1;
}
for ($i = 0; $i < 10; $i++) {
echo "Memory usage: ". memory_get_usage(). "\n";
$x = new ClsA();
$x->propA = $x;
}
最佳答案
这是因为 PHP 垃圾收集器并不总是在您分配的确切时刻回收您的对象(ClsA
实例)使用的内存您对另一个对象的引用 ($x
)。 PHP 完全使用引用计数和垃圾收集。
如果您在每个循环上强制进行垃圾回收,您将看到您的内存占用量将保持不变:
<?php
class ClsA {
public $propA = 1;
}
for ($i = 0; $i < 10; $i++) {
gc_collect_cycles();
echo "Memory usage: ". memory_get_usage(). "\n";
$x = new ClsA();
$x->propA = $x;
}
输出:
$ php test.php
Memory usage: 396296 <-- before the first ClsA allocation
Memory usage: 396384
Memory usage: 396384
Memory usage: 396384
Memory usage: 396384
Memory usage: 396384
Memory usage: 396384
Memory usage: 396384
Memory usage: 396384
Memory usage: 396384
更多(技术)信息在这里:https://www.php.net/manual/en/features.gc.collecting-cycles.php
关于php - 在 PHP7 扩展中创建循环对象时发生内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55535412/