在调试一段耗尽内存的代码时,我发现了一个非常有趣的问题,最重要的是我不知道如何修复它。
应用程序大致由一个Survey
对象组成,该对象包含许多Question
个对象。问题对象包含对他们所处的调查的引用,例如,这需要能够从其他问题中获取答案。
以下循环导致内存溢出:
foreach ( $survey_ids_arr as $survey_id ) {
$Survey = new Survey( $survey_id );
}
Survey构造函数中没有发生任何异乎寻常的事情;
并且从查看代码开始,您会说在每次迭代中都会从内存中清除对象,因为$ Survey变量会被覆盖。对??错了:))
当脚本经过循环时内存堆积 - 添加memory_get_usage()
调用显示Survey对象使用的内存未按预期释放,此时另一个对象被分配给{{ 1}}变量。即使在循环结束时调用$Survey
也不会释放内存。
罪魁祸首是在创建时传递给Question对象的unset( $Survey )
引用。这些引用可以防止对象从内存中清除 - 正如php.net上的手册所述:
一旦删除了对特定对象的所有引用,就会调用析构函数方法
那么是什么阻止了对象的清理,就是它对自身的引用。很好,对吧? :)
所以,问题是我的对象是一个记忆杀手。不幸的是,我想不出一个解决方案(除了编写一个丑陋的方法来清除问题并从循环中调用它)。调查中的析构函数不是一个选项;如上所述,这不称为,因为 Question对象仍有引用。
有什么想法吗?有人必须已经遇到这个问题 - 包含父对象的子对象不是一个不常见的架构,是吗?
答案 0 :(得分:2)
所以,这就是答案:切换到PHP 5.3,因为这个问题已经resolved了。如果你必须使用PHP< 5.3.0,您有责任释放在圆形参考中捕获的对象。一种可能的方法是引入特殊方法,剥离子对象的链接以允许它们被GC
收集
P.S。也可能对某些人有用,Doctrine 1.2
在模型中有这样的链接,因此它会导致内存泄漏,特别是如果从数据库中获取大量实体。如果您遇到这个问题,请尝试(1)减少获取的实体数量(例如,水合物作为数组),(2)处理具有原始sql请求的实体。