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

标签 php c php-extension

以下是我创建的测试函数(针对 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/

相关文章:

php - 如何在 codeigniter View 页面中使用用户 ID 打印(获取)用户名

php - ffmpeg-php 创建视频缩略图

php - Laravel : random error : SQLSTATE[3D000]: Invalid catalog name: 1046 No database selected

c - PC lint 错误 19 "useless declaration "

php fopen 相对路径损坏 - 神秘

c - argv[n] 是可写的吗?

c - sprintf() 中的意外结果

docker - 从 php 以外的容器运行 `docker-php-ext-install`

apache - sudo : pecl7. 2-sp:找不到命令

memcached - phpinfo() 中列出的 php-fpm 扩展失败,返回 "Class not found"