PHP传引用会增加内存使用量

4

在调用函数并传递大字符串时,我通常通过引用传递。这样做的目的是使PHP不通过传递字符串的副本来传递值,从而降低内存使用量。然而,在某些情况下,我注意到相反的效果。

在下面的示例中,在将字符串通过引用传递到函数中时,在is_string()调用时,峰值内存使用量翻倍。

代码:

$buf = '';
report_memory(__LINE__);

$buf = file_get_contents('./20MB.pdf');
report_memory(__LINE__);

example($buf);
report_memory(__LINE__);

function example(& $str) {
    report_memory(__LINE__);
    is_string($str);
    report_memory(__LINE__);
}

function report_memory($line=0) {
    echo 'Line: ' . str_pad($line,3) . ' ';
    echo 'Mem: '  . str_pad(intval(memory_get_usage()/1024     ) . 'K',8) . ' ';
    echo 'Peak: ' . str_pad(intval(memory_get_peak_usage()/1024) . 'K',8) . ' ';
    echo "\n";
}

输出:

Line: 2   Mem: 625K     Peak: 631K
Line: 5   Mem: 21058K   Peak: 21076K
Line: 11  Mem: 21058K   Peak: 21076K
Line: 13  Mem: 21058K   Peak: 41494K
Line: 8   Mem: 21058K   Peak: 41494K

将函数example()更改以删除引用:
function example($str) {
    report_memory(__LINE__);
    is_string($str);
    report_memory(__LINE__);
}

输出:

Line: 2   Mem: 625K     Peak: 631K
Line: 5   Mem: 21058K   Peak: 21076K
Line: 11  Mem: 21058K   Peak: 21076K
Line: 13  Mem: 21058K   Peak: 21076K
Line: 8   Mem: 21058K   Peak: 21076K

这是我所期望的。那么当变量是引用时,为什么使用is_string()会使内存翻倍呢?
环境是运行着标准PHP 5.3.3的CentOS 6.6。

1
也许你应该考虑将这个问题作为一个问题提出到 bugs.php.net,那里你更有可能从 PHP 核心开发人员得到明确的答案...虽然其中一些人经常浏览 StackOverflow,可能会看到你的问题,但通过询问编写 PHP 本身的人来获得准确的答案更为可靠。 - Mark Baker
如果你正在详细评估 PHP,那么使用像 Vulcan Logic Dumper 这样的工具,对代码进行操作码级别的分析,可能会让你了解 PHP 是如何在底层运作的。 - Mark Baker
@Mark Baker:目前我认为这是我对PHP工作方式的了解不足导致的问题(而不是PHP的错误或实现决定)。不过您提供的两个好主意。谢谢! - Bob Stack
作为学习PHP工作原理的一种方式,阅读源代码总是很有用的(尽管很难追踪参数是如何传递给函数的,而不仅仅是查看函数本身的代码),但VLD是一个非常有用的工具。 - Mark Baker
这个问题已经在PHP 7.2.24中得到了解决(多数情况下)。 - Bob Stack
1个回答

1

Zend引擎使用惰性复制机制。在变量被修改之前,它不会创建变量的副本。PHP创建了一组结构来维护引用,这就是为什么通过引用传递变量实际上“更慢”的原因。


我理解lazy-copy。这不是问题所在。问题是:为什么按引用传递会增加峰值内存使用量,在这个例子中,调用is_string()? - Bob Stack

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接