为什么PHP的垃圾收集器会降低性能,以及如何在没有它的情况下管理内存?

时间:2013-01-24 12:29:44

标签: php memory-management garbage-collection unset

这与PHP 5.3 Cli应用程序有关,该应用程序以复杂的方式处理大量数据,需要数小时才能运行。有人发现关闭垃圾收集使其运行速度更快(可能高达50%)。

我遇到的唯一一篇文章提及此次广告效果是http://derickrethans.nl/collecting-garbage-performance-considerations.html。我不确定我是否完全遵循它,但它似乎表明它只适用于带有大量循环引用的代码。

有人可以对此有所了解吗?

另外,鉴于我们已关闭gc,有没有办法手动减少内存?建议使用unset()。快速测试表明,无论对象的大小如何,unset()都会释放80个左右的字节。这表明它只是取消了参考,这是我在网上看到的。我是否正确地认为,当变量超出范围时,即使没有垃圾收集,这些80个字节也会被释放?

2 个答案:

答案 0 :(得分:4)

您刚刚禁用了循环引用GC。常规的仍然有效。

常见的GC测试,无论是否有zval s(“内存”),都没有被任何变量或属性引用,并且将释放此内存。当两个或多个对象直接或间接地相互引用时,循环引用

$a = new stdClass;
$b = new stdClass;
$a->b = $b;
$b->a = $a;
unset($a, $b);

现在两个对象互相引用,但它们都没有从其他任何地方引用,因此它们无法访问。这就是循环引用GC尝试检测的内容,但是为了找到它们,它会迭代每个已知对象,并查找是否存在“来自外部”的引用。它有点复杂,但简化了它;)所以在有许多参考的结构中,特别是循环的,这是一项艰巨的任务。

值得一提:使用unset()只删除引用,但不要释放内存(直接)。这是由GC稍后完成的(它做得很好:))

答案 1 :(得分:2)

您可以使用unset手动删除代码中的周期。您可以通过实现__destruct函数来清除类中的循环。 unset引用其他对象的所有私有,受保护或公共变量。

如果你将它应用于现有程序,那将非常繁琐,但它是可行的。


class A {
    public $ref;
    public function __destruct() {
        unset($this->ref);
        echo "destruct";
    }
}
$a1 = new A();
$a2 = new A();
$a1->ref = $a2;
$a2->ref = $a1;

工作:

unset($a1, $a2);
echo "--";
// prints --destructdestruct (in 5.3)

这有效:

$a1->__destruct();
unset($a1, $a2);
echo "--";
// prints destructdestructdestruct-- (in 5.3)