为啥 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 测试,无论是否有 zval
s(“内存”),不再被任何变量或属性引用,并将释放此内存。循环引用是指两个或多个对象直接或间接相互引用
$a = new stdClass;
$b = new stdClass;
$a->b = $b;
$b->a = $a;
unset($a, $b);
现在两个对象相互引用,但它们都没有从其他任何地方引用,所以它们是不可访问的。这就是循环引用 GC 试图检测的内容,但要找到它们,它会遍历每个已知对象并找出是否存在“来自外部”的引用。它有点复杂,但简化了 ;) 所以在有很多引用的结构中,尤其是循环的,这是一项艰巨的任务。
值得一提:使用unset()
,您只会删除引用,但不会(直接)释放内存。这是由 GC 稍后完成的(它做得很好:))
【讨论】:
我以为可能是这样,但是手册很不清楚。那么,普通的不能禁用吗? (不是我想,只是感兴趣) @naomi 是的,你不能禁用它。也没有理由(影响非常小),因为您无法自己从 PHP 中释放内存(unset()
不会这样做),您将遇到一个大问题:D以上是关于为啥 PHP 的垃圾收集器会降低性能,没有它如何管理内存?的主要内容,如果未能解决你的问题,请参考以下文章