在 PHP7 扩展中创建循环对象时内存泄漏



以下是我创建的测试函数(适用于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 代码的输出。

转储1 ---- object(ClsA)#1 (1) { ["propA"]=>*递归* } 内存使用情况:351336 内存使用情况:351392 内存使用情况:351448 内存使用量:351504 内存使用量:351560 内存使用量:351616 内存使用量:351672 内存使用量:351728 内存使用情况:351784 内存使用量:351840 转储2 ---- object(clsA)#11 (1) { ["propA"]=>*递归* } 转储3 ---- object(clsA)#11 (1) { ["propA"]=>NULL }

var_dump()结果看起来不错,但内存使用量不断增加。

当我使用ZVAL_COPY_VALUE而不是ZVAL_COPY时,内存使用量不会增加,但它会在 DUMP3 中产生奇怪的输出。

转储3 ---- *递归*

可能是函数返回损坏的对象。

谁能告诉我扩展功能出了什么问题?

编辑1:发布问题后,我注意到memory_get_usage(true)没有增加。这是我犯的错误吗?

编辑2:以下PHP程序(纯PHP,无扩展)显示内存使用量增加。这是一个PHP错误还是我误解了什么?我正在使用 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垃圾回收器并不总是在您将引用($x)分配给另一个对象时回收对象(ClsA实例)使用的内存。PHP 完全使用 ref 计数和垃圾回收。

如果在每个循环上强制进行垃圾回收,您将看到内存占用量将保持不变:

<?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

相关内容

  • 没有找到相关文章

最新更新