PHP何时在长时间运行的脚本中运行垃圾回收?

mcf*_*edr 3 php garbage-collection

我正在编写一个PHP cli程序,该程序是队列系统的辅助进程。

我认为在这种情况下,PHP会不时收集垃圾,并且不会经常达到内存限制。

事实并非如此。

笔记

  • 在PHP 7上运行
  • 它是一个长期运行的脚本
  • zend.enable_gc = 1
  • 没有全局变量

mcf*_*edr 5

归结为这个。您必须通过调用手动触发垃圾收集gc_collect_cycles()

我写了很多代码来尝试追踪并归结为两个脚本:

这不会崩溃:

for($i = 0;$i < 100;$i++) {
    useMemory();
    gc_collect_cycles();
}
Run Code Online (Sandbox Code Playgroud)

这崩溃了:

for($i = 0;$i < 100;$i++) {
    useMemory();
}
Run Code Online (Sandbox Code Playgroud)

这是在Blackfire上比较这些脚本的链接

如您所见,当您不调用gc_collect_cycles它时,它永远不会发生,并且您达到了内存限制,PHP杀死了自己。

PHP甚至没有利用此机会进行GC本身。在PHP-DEV邮件列表上讨论了其背后的原因,但是基本上归结为__destruct当达到内存限制时如何运行需要内存的方法的复杂性。(也在Bug跟踪器#60982上)。

内存使用功能:

这是我用来“浪费”内存的代码,它有目的地创建只能由垃圾收集器清除的循环引用。请注意,如果没有这些循环,则一旦超出范围,这些对象将通过引用计数进行清理。

class Big {
    private $data;
    public function __construct($d = 0) {
        for($i = 0;$i< 1024 * 10;$i++) {
            $this->$i = chr(rand(97, 122));
        }
    }
}

function useMemory() {
    $a = new Big();
    $b = new Big();

    $a->b = $b;
    $b->a = $a;
}
Run Code Online (Sandbox Code Playgroud)