2

不久前,在对它们进行了一些操作之后,我就赋值变量本身进行了辩论。

将变量分配给自身 [ AI ]:

echo memory_get_usage() . "\n"; // 645680
$repeatedString = str_repeat('Hello,', 10000);
echo memory_get_usage() . "\n"; // 705944, AI_delta1 = 60264
$repeatedString = explode(',', $repeatedString);
echo memory_get_usage() . "\n"; // 3337888, AI_delta2 = 2631944
echo memory_get_peak_usage() . "\n"; // AI_peak = 3401024

将变量分配给另一个变量 [ AAV ]:

echo memory_get_usage() . "\n"; // 645752
$repeatedString = str_repeat('Hello,', 10000);
echo memory_get_usage() . "\n"; // 706024, AAV_delta1 = 60272
$explodedString = explode(',', $repeatedString);
echo memory_get_usage() . "\n"; // 3398256, AAV_delta2 = 2692232
echo memory_get_peak_usage() . "\n"; // AAV_peak = 3400984

我在这两种情况下都创建了内存使用测试并减去值:

AAV_delta1 - AI_delta = 8
AAV_delta2 - AI_delta2 = 60288
AAV_peak - AI_peak = -40

根据这个结果,使用哪种方法并不重要,内存使用 - 相同。$repeatedString 我是否应该在下面的代码中使用变量只是一个问题。

我的结论是正确的还是我的测试不正确?

为什么会这样?

还有一个问题:AAV_delta1 - AI_delta = 8,我希望它应该等于 0。为什么等于 8?

注意:内存使用量可能因您的系统而异。

PHP 版本:5.3.5-1ubuntu7.11。

4

1 回答 1

4

在 AAV 中,有两个数据副本,因为每个变量都必须保留其数据。它们都必须持续存在,直到它们各自的变量被重新分配或超出范围。

在 AI 中,数据暂时有两个副本。一旦分配发生,就不再需要原始值。但是,在垃圾回收发生之前,它使用的内存不会被回收。

如果您在分配后立即检查内存使用情况,您不会注意到差异,因为可能还没有 GC。如果你强制 GC,你应该会看到 AI 使用的内存比 AAV 少。

您还可以通过在分配后取消设置原始变量(称为AAVU)在 AAV 中获得相同的内存使用改进:

$explodedString = explode(",", $repeatedString);
unset($repeatedString); // or $repeatedString = false;

与 AI 一样,您必须强制 GC 立即注意到内存使用量的减少。

更新:

因为 PHP 使用引用计数进行正常的内存管理,AI 应该立即回收字符串使用的内存。字符串以引用计数 1 开始。当它被传递给explode()时,引用计数增加到 2(对于爆炸的参数变量的引用)。返回时explode(),参数变量的作用域结束,引用计数返回 1。然后,当赋值$repeatedString发生时,引用计数下降到 0,字符串的内存被回收。

gc_collect_cycles()只需要回收作为循环一部分的数组和对象使用的内存。要查看其影响,请尝试以下代码:

gc_enable();
echo "Begin: " .  memory_get_usage() . "\n";
$array = array(str_repeat('Hello,', 10000));
$array[] =& $array; // Create circular reference
echo "After allocate: " . memory_get_usage() . "\n";
unset($array);
echo "After unset: " . memory_get_usage() . "\n";
gc_collect_cycles();
echo "After GC: " . memory_get_usage() . "\n";

结果:

Begin: 226088
After allocate: 286640
After unset: 286552
After GC: 226088

有关详细信息,请参阅PHP 垃圾收集文档

于 2013-01-04T07:17:38.190 回答