PHP首次echo会让内存使用量增加x字节

楚天乐 261 0 条

始于群友提出的一个问题

<?php
$m1 = memory_get_usage();
echo 'm1:' . $m1;
$arr1 = [];
for($i = 0; $i < 1000000; $i++){
    $arr1[] = $i;
}
unset($i);
echo PHP_EOL;
$m2 = memory_get_usage();
echo 'm2:' . $m2;
$arr2 = $arr1;
echo PHP_EOL;
echo 'm2-m1:' . ($m2 - $m1);
echo PHP_EOL;
$m3 = memory_get_usage();
echo 'm3:' . $m3;
echo PHP_EOL;
echo 'm3-m2:' . ($m3 - $m2);
$arr3 = [];
foreach ($arr2 as $key => $value) {
    $arr3[] = $value;
}
// unset($m1,$m2);
$m4 = memory_get_usage();
echo PHP_EOL;
echo 'm4:' . $m4;
echo PHP_EOL;
echo 'm4-m3:' . ($m4-$m3);

这段代码的输出如下,为什么(m4-m3)比(m2-m1)少32字节?

m1:388416
m2:27651488
m2-m1:27263072
m3:27651488
m3-m2:0
m4:54914528
m4-m3:27263040

分析

$m1和$m2之间,除了echo输入,只做了一件事。给$arr1填充1000000个元素。

$arr1 = [];
for($i = 0; $i < 1000000; $i++){
    $arr1[] = $i;
}
unset($i); // 销毁循环变量

$m3和$m4之间,除了echo输入,也只做了一件事。给$arr1填充1000000个元素。

$arr3 = [];
foreach ($arr2 as $key => $value) { // $arr2是$arr1的引用
    $arr3[] = $value;
}

我们化简一下这段代码,把不相关元素都去掉。$m3和$m4之间,使用$arr1做数据源.

$m1 = memory_get_usage();
echo 'm1:' . $m1 . PHP_EOL;
$arr1 = [];
for($i = 0; $i < 1000000; $i++){
    $arr1[] = $i;
}
unset($i);
$m2 = memory_get_usage();
echo 'm2-m1:' . ($m2-$m1) . PHP_EOL;

$arr3 = [];
foreach ($arr1 as $key => $value) {
    $arr3[] = $value;
}
$m3 = memory_get_usage();
echo 'm3-m2:' . ($m3-$m2) . PHP_EOL;

这段代码输出如下,和原始代码等效。

λ php index.php
m1:387336
m2-m1:27263072
m3-m2:27263040

进一步化简,把所有echo移到尾部

$m1 = memory_get_usage();

$arr1 = [];
for($i = 0; $i < 1000000; $i++){
    $arr1[] = $i;
}
unset($i);
$m2 = memory_get_usage();
$arr3 = [];
foreach ($arr1 as $key => $value) {
    $arr3[] = $value;
}
$m3 = memory_get_usage();

echo 'm1:' . $m1 . PHP_EOL;
echo 'm2-m1:' . ($m2-$m1) . PHP_EOL;
echo 'm3-m2:' . ($m3-$m2) . PHP_EOL;

输出结果,两次内存用量相等了,问题不存在了。

λ php index.php
m1:387336
m2-m1:27263040
m3-m2:27263040

所以这32字节多在echo上。我们在m1和m2,m2和m3之间增加echo试试看。

test 1: m1后增加echo

$m1 = memory_get_usage();
echo "xxxxxxx" . PHP_EOL;            // 增加echo
$arr1 = [];
for($i = 0; $i < 1000000; $i++){
    $arr1[] = $i;
}
unset($i);
$m2 = memory_get_usage();
$arr3 = [];
foreach ($arr1 as $key => $value) {
    $arr3[] = $value;
}
$m3 = memory_get_usage();

echo 'm1:' . $m1 . PHP_EOL;
echo 'm2-m1:' . ($m2-$m1) . PHP_EOL;
echo 'm3-m2:' . ($m3-$m2) . PHP_EOL;

结果

m1:387400
m2-m1:27263072            // 多了32
m3-m2:27263040

test 2: m2后增加echo

$m1 = memory_get_usage();
$arr1 = [];
for($i = 0; $i < 1000000; $i++){
    $arr1[] = $i;
}
unset($i);
$m2 = memory_get_usage();
echo "xxxxxxx" . PHP_EOL;        // 增加echo
$arr3 = [];
foreach ($arr1 as $key => $value) {
    $arr3[] = $value;
}
$m3 = memory_get_usage();

结果

m1:387400
m2-m1:27263040
m3-m2:27263072            // 多了32

test 3: m1和m2一起加echo

$m1 = memory_get_usage();
echo "xxxxxxx" . PHP_EOL;
$arr1 = [];
for($i = 0; $i < 1000000; $i++){
    $arr1[] = $i;
}
unset($i);
$m2 = memory_get_usage();
echo "xxxxxxx" . PHP_EOL;
$arr3 = [];
foreach ($arr1 as $key => $value) {
    $arr3[] = $value;
}
$m3 = memory_get_usage();

echo 'm1:' . $m1 . PHP_EOL;
echo 'm2-m1:' . ($m2-$m1) . PHP_EOL;
echo 'm3-m2:' . ($m3-$m2) . PHP_EOL;

结果

m1:387400
m2-m1:27263072            // 多了32
m3-m2:27263040

test4 echo数据量和内存增量有什么关系

echo 1字节

$m1 = memory_get_usage();
echo str_repeat("x",1) . PHP_EOL;
$m2 = memory_get_usage();
echo 'm2-m1:' . ($m2-$m1) . PHP_EOL;

结果

m2-m1:32

echo 10020字节

$m1 = memory_get_usage();
echo str_repeat("x",10020) . PHP_EOL;
$m2 = memory_get_usage();
echo 'm2-m1:' . ($m2-$m1) . PHP_EOL;

结果

m2-m1:32

内存增量都是32字节

在网上试了几个php sandbox,发现每个版本php内存增量是不一样的。

总结

  • 首次echo会使内存用量增加,仅首次会增加
  • 内存用量增加32字节,不管echo内容是多少字节。
  • 不同版本php字节数会不同

本机测试环境

PHP 7.2.10 (cli) (built: Sep 13 2018 01:01:10) ( ZTS MSVC15 (Visual C++ 2017) x86 )


发表我的评论
'
昵称 (必填)
邮箱 (必填)
网址