为啥 PHP 的垃圾收集器会降低性能,没有它如何管理内存?

Posted

技术标签:

【中文标题】为啥 PHP 的垃圾收集器会降低性能,没有它如何管理内存?【英文标题】:Why does PHP's garbage collector slow down performance, and how to manage memory without it?为什么 PHP 的垃圾收集器会降低性能,没有它如何管理内存? 【发布时间】:2013-01-08 05:07:04 【问题描述】:

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

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

有人能解释一下吗?

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

【问题讨论】:

【参考方案1】:

您可以使用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)

【讨论】:

你得到我的+1 用于第二次使用__destruct() 我觉得有用曾经 :D(第一个是“关闭资源、数据库连接、文件、. ..") 好的,所以,unset() 不会释放内存,但它会删除循环引用,因此在禁用循环引用收集器时使用它(在适当的情况下)是个好主意。我说对了吗? 是的,您可以使用unset 删除循环。 unset 本身不会释放内存,它会清理引用。如果一条数据没有引用,它就会被清理掉。 GC 对引用计数很容易,但很难检测循环。 __destroy 永远不会被调用,除非你的对象已经被销毁(也就是说,内存将被释放)。使用 CPU 时间来取消设置对象中的任何引用不会提高性能。但是,如果您的析构函数可以中断其他对象之间的循环(而不是取消设置从被破坏对象到另一个对象的一个​​或多个引用),那么它是有意义的。 @MikkoRantalainen 这似乎确实如此。在调用unset 之前,您必须在对象上手动调用__destruct()。请参阅我更新的答案中的示例代码。【参考方案2】:

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

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

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

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

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

【讨论】:

我以为可能是这样,但是手册很不清楚。那么,普通的不能禁用吗? (不是我想,只是感兴趣) @naomi 是的,你不能禁用它。也没有理由(影响非常小),因为您无法自己从 PHP 中释放内存(unset() 不会这样做),您将遇到一个大问题:D

以上是关于为啥 PHP 的垃圾收集器会降低性能,没有它如何管理内存?的主要内容,如果未能解决你的问题,请参考以下文章

偶尔会遇到长时间的垃圾收集延迟,为啥?

为啥在执行 Java Stream 终端操作时对象没有被垃圾收集?

如何弄清楚为啥垃圾收集器使用了我 90% 的 CPU?

CMS垃圾收集器

如何提高 UITableVIew 的性能?

ruby的内存管理