1

测试一:

class Entity { }

$entities = array();
echo "START: ". number_format(memory_get_usage()) . "\n";
for($i = 0; $i < 100000; ++$i)
{
    $entities[] = new Entity();
}
echo "BEFORE UNSET: ". number_format(memory_get_usage()) . "\n";
unset($entities);
echo "AFTER UNSET: ". number_format(memory_get_usage()) . "\n";

输出:

START: 631,664
BEFORE UNSET:44,404,904
AFTER UNSET: 8,954,568

测试二:

class Entity { }

$entities = array();
echo "START: ". number_format(memory_get_usage()) . "\n";
for($i = 0; $i < 100000; ++$i)
{
    $entity = new Entity();
    $entities[] = &$entity;
}
echo "BEFORE UNSET: ". number_format(memory_get_usage()) . "\n";
unset($entities);
echo "AFTER UNSET: ". number_format(memory_get_usage()) . "\n";

输出:

START: 631,664
BEFORE UNSET: 10,480,480
AFTER UNSET: 631,752

在我遇到内存限制问题后,我玩了一下......

所以在那之后我想知道垃圾收集是如何工作的:

  1. 为什么测试一比测试需要更多的内存?
  2. 为什么在测试一中取消设置数组后 php 会保留内存?

谢谢戴夫

4

2 回答 2

1
  1. 第一个是您将实际对象保存到数组中的每个值,因此当您取消设置数组时,这些对象仍然存在。
    • 这就是这个数组占用更多内存的原因——它存储的是实际对象
  2. 第二个,您只是保存对对象的引用(仅在 for 循环的范围内),一旦未设置,对象就消失了。
    • 这个数组占用内存少的原因是它只存储对对象的引用。

因此,如果您执行此处的操作:

$entities = array();
echo "START: ". number_format(memory_get_usage()) . "\n";
for($i = 0; $i < 100000; ++$i)
{
    $entities[] = new Entity;
}
echo "BEFORE UNSET: ". number_format(memory_get_usage()) . "\n";
foreach($entities as &$entity) {
    unset($entity);
}
unset($entities);
echo "AFTER UNSET: ". number_format(memory_get_usage()) . "\n";

并且您取消设置数组中的每个对象。您得到与第二次尝试相同的结果:

例子:

开始:3,237,720 未设置
前:21,297,640 未设置
后:3,237,488

演示:http ://codepad.org/oUjzA46D

于 2012-04-05T17:59:39.007 回答
1

为什么测试一比测试二需要更多的内存?

PHP 为存储标识符分配的内存比为引用分配的内存多(您的第一个测试按标识符分配)。

手册

PHP 引用是一个别名,它允许两个不同的变量写入相同的值。从 PHP 5 开始,对象变量不再包含对象本身作为值。它只包含一个对象标识符,允许对象访问者找到实际对象。当一个对象通过参数发送、返回或分配给另一个变量时,不同的变量不是别名:它们持有标识符的副本,它指向同一个对象。

这使得标识符有些神奇,并且它们是经过特殊处理的。

为什么在测试一中取消设置数组后php会保留内存?

unset仅仅标记一个变量的内存,供 GC 算法释放;它不会立即释放内存。当我运行您的第一个测试时,会释放大量内存(尽管没有第二个测试那么多,可能是由于分配了更大的大小)。

于 2012-04-05T18:45:07.663 回答