PHP内存取消设置对象的数组

时间:2012-04-05 17:56:34

标签: php

测试一:

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在测试 one
  3. 中取消设置数组后会保留内存

    thx dave

2 个答案:

答案 0 :(得分:1)

  1. 第一个是将实际对象保存到数组中的每个值,因此当您取消设置数组时,这些对象仍然存在。
    • 这就是为什么这个数组占用更多内存 - 它存储实际对象
  2. 第二个只是保存对象的引用(仅在for循环的范围内),一旦取消设置,对象就消失了。
    • 此阵列占用更少内存的原因是它只将引用存储到对象中。
  3. 所以如果你做的就是这里:

    $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";
    

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

    示例:

      

    START:3,237,720
      在UNSET之前:21,297,640
      在UNSET之后:3,237,488

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

答案 1 :(得分:1)

  

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

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

来自manual

  

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

这使得标识符有点神奇,并且它们是专门处理的。

  

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

unset仅标记变量的内存以便通过GC算法释放;它不会释放内存。当我运行第一次测试时,会释放大量内存(尽管没有第二次测试那么多,可能是因为分配了更大的内容)。