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


Why does PHP's garbage collector slow down performance, and how to manage memory without it?

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

我遇到的唯一一篇提到这种性能影响的文章是 http://derickrethans.nl/collecting-garbage-performance-considerations.html。我不确定我是否完全遵循它,但它似乎表明它仅适用于具有大量循环引用的代码。

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

另外,鉴于我们已经关闭了gc,有没有办法手动减少内存?有人建议使用 unset()。一个快速的测试表明,无论对象的大小如何,unset() 都会释放大约 80 个字节。这表明它只是取消设置引用,我在网上阅读的内容证实了这一点。我是否正确认为,当变量超出范围时,即使没有垃圾回收,这八十个字节也会被释放?

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

常见的GC测试,无论是否存在zval s("内存"),都不再被任何变量或属性引用,并将释放此内存。循环引用是指两个或多个对象直接或间接相互引用

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

现在,这两个对象相互引用,但它们都不是从其他任何地方引用的,因此无法访问它们。这就是循环引用GC试图检测的内容,但要找到它们,它会遍历每个已知对象,并找出是否存在"来自外部"的引用。它有点复杂,但简化就是这样;)因此,在具有许多引用的结构中,尤其是圆形引用,这是一项艰巨的任务。

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

您可以使用

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)