通过引用自身来解构对象

时间:2011-08-18 12:15:42

标签: php oop destructor

在调试一段耗尽内存的代码时,我发现了一个非常有趣的问题,最重要的是我不知道如何修复它。

应用程序大致由一个Survey对象组成,该对象包含许多Question个对象。问题对象包含对他们所处的调查的引用,例如,这需要能够从其他问题中获取答案。


以下循环导致内存溢出:

foreach ( $survey_ids_arr as $survey_id ) {
    $Survey = new Survey( $survey_id );
}

Survey构造函数中没有发生任何异乎寻常的事情;

  • 从数据库中提取其属性
  • 从数据库中提取所有问题的属性
  • 为每个问题创建一个Question对象(将引用传递给$ this)
  • 将所有Question对象添加到内部数组

并且从查看代码开始,您会说在每次迭代中都会从内存中清除对象,因为$ Survey变量会被覆盖。对??错了:))

当脚本经过循环时内存堆积 - 添加memory_get_usage()调用显示Survey对象使用的内存未按预期释放,此时另一个对象被分配给{{ 1}}变量。即使在循环结束时调用$Survey也不会释放内存。


罪魁祸首是在创建时传递给Question对象的unset( $Survey )引用。这些引用可以防止对象从内存中清除 - 正如php.net上的手册所述:

  

一旦删除了对特定对象的所有引用,就会调用析构函数方法

那么是什么阻止了对象的清理,就是它对自身的引用。很好,对吧? :)

所以,问题是我的对象是一个记忆杀手。不幸的是,我想不出一个解决方案(除了编写一个丑陋的方法来清除问题并从循环中调用它)。调查中的析构函数不是一个选项;如上所述,这不称为,因为 Question对象仍有引用。

有什么想法吗?有人必须已经遇到这个问题 - 包含父对象的子对象不是一个不常见的架构,是吗?

1 个答案:

答案 0 :(得分:2)

所以,这就是答案:切换到PHP 5.3,因为这个问题已经resolved了。如果你必须使用PHP< 5.3.0,您有责任释放在圆形参考中捕获的对象。一种可能的方法是引入特殊方法,剥离子对象的链接以允许它们被GC收集

P.S。也可能对某些人有用,Doctrine 1.2在模型中有这样的链接,因此它会导致内存泄漏,特别是如果从数据库中获取大量实体。如果您遇到这个问题,请尝试(1)减少获取的实体数量(例如,水合物作为数组),(2)处理具有原始sql请求的实体。